2015-05-11 6 views
8

Ich habe kürzlich seltsames Verhalten in meiner Anwendung gesehen, die ich nicht wirklich erklären kann. Sie kommen sehr selten vor, so dass ich sie nicht reproduzieren kann. Während der Ort, an dem diese Probleme auftreten, sich ändert, scheint der gemeinsame Teil zu sein, dass ein Array seine Größe ändert, nachdem es erstellt wurde (ich weiß, das ist nicht möglich, daher: seltsames Verhalten).Array-Längenänderungen in openjdk

java.lang.StringIndexOutOfBoundsException: String index out of range: 86 
    at java.lang.String.checkBounds(String.java:409) 
    at java.lang.String.<init>(String.java:577) 
    at com.acunia.fleet.diagnostics.providers.tacho.VDOKLineInputParser.getRealDriverID(Unknown Source) 

Der Code, der dies verursachen würde:

Ein paar Beispiele meinen Punkt klar machen

public String getRealDriverID(byte[] buffer) { 
    if (buffer.length > 86 && isDriverCardInserted(buffer)) { 
    return new String(buffer, 70, 16); 
    } 
    return null; 
} 

So prüfen wir zuerst, dass der Puffer groß genug ist (mehr als 86 Bytes) bevor Sie versuchen, aus ihnen eine Zeichenfolge zu erstellen.

Ein zweites Beispiel:

java.lang.ArrayIndexOutOfBoundsException: -1 
    at java.lang.String.lastIndexOf(String.java:1889) 
    at java.lang.String.lastIndexOf(String.java:1835) 
    at java.lang.String.lastIndexOf(String.java:1817) 
    at com.acunia.service.position.nmea.comm.CommPositionProvider.isValid(Unknown Source) 

Die Linie, die diese Ausnahme verursacht, ist:

int csi = line.lastIndexOf("*"); 

ich an der openjdk String.java Quelle hatte einen Blick, konnte aber nicht einen Fehler finden, es sei denn Arrays könnten plötzlich die Größe ändern, nachdem sie erstellt wurden.

Die einzige Referenz online, die ich finden konnte, die möglicherweise verwandt sein könnte, war als Openjdk-Fehler: https://bugs.openjdk.java.net/browse/JDK-6817012. Dieser Fehler wurde als "kein Problem" markiert, obwohl ich beim Lesen nicht wirklich sagen kann, ob das Problem, das erwähnt wird, nicht als Fehler erkannt wird, oder ob die Person, die den Fehler geschlossen hat, diesen Fehler nicht sieht würde Probleme verursachen.

Wenn jemand jemals auf ein ähnliches Problem gestoßen ist, würde ich es sehr schätzen, davon zu hören. So wie es aussieht, ist das Problem zu instabil, um es mit anderen Versionen von openjdk zu beheben.

Problem wurde am gesehen:

hardware: custom arm platform 
java version "1.6.0_31" 
OpenJDK Runtime Environment (IcedTea6 1.13.3) (6b31-1.13.3-1~deb7u1) 
OpenJDK Zero VM (build 23.25-b01, mixed mode) 
Linux 3.2.0 #1 Fri Jun 20 10:25:16 CEST 2014 armv7l GNU/Linux 
+3

Sie verwenden Java 6. Java 7 nur Ende ihrer Lebensdauer erreicht. Sie sollten Ihr Java wirklich verbessern. – icza

+3

Das zweite Beispiel wäre leicht zu erklären, wenn das Zeichen nicht im String erscheint. In diesem Fall gibt lastIndexOf -1 zurück, und in der Beschwerde geht es darum, den Index -1 zu verwenden. –

+0

Ich würde auch empfehlen, Ihr Java auf 8 zu aktualisieren, wenn möglich. Und vorzugsweise die Oracle-Version. OpenJDK hat mir nichts als Kopfschmerzen gegeben. –

Antwort

3

Sie erstellen das neue Stringbyte[] Array ohne die Charset angeben. Also meine Vermutung ist, dass System-Standard-Zeichensatz geändert wurde und Sie das Verhalten Änderungen sehen. Ich würde vorschlagen, den Zeichensatz immer explizit anzugeben. Zum Beispiel:

return new String(buffer, 70, 16, "UTF-8"); 
+0

Wir haben diese Möglichkeit untersucht. Das System ist größtenteils schreibgeschützt, daher kann der Standardzeichensatz nicht geändert werden. Außerdem wäre das Problem, wenn es geändert worden wäre, an vielen Stellen zu sehen gewesen, und wir sahen nur eine einzige Ausnahme während des gesamten Laufs. Schließlich scheint die checkBounds-Methode in java.lang.String nur anhand der Größe des Byte-Arrays zu überprüfen, wobei charset nicht berücksichtigt wird. –

+0

Der Zeichensatz hat sich möglicherweise nicht geändert, aber die Eingabe in das System, das das ausgelöst hat, ist möglicherweise nicht sehr häufig aufgetreten? – aioobe

+0

Die Eingabe wird ungefähr 4 Mal pro Sekunde für diesen bestimmten Thread ausgelöst. Andere Threads werden noch häufiger ausgelöst. –

4

Dies ist höchstwahrscheinlich ein Problem mit den Bytes und dem Systemzeichensatz. The documentation ausdrücklich sagt:

Das Verhalten dieses Konstruktor, wenn das angegebene Bytes in dem Standard-Zeichensatz nicht gültig ist, ist nicht spezifizieren.

Sie können dies umgehen, indem sie ausdrücklich die richtige charset Bereitstellung:

new String(buffer, 70, 16, StandardCharsets.UTF_8) 
+0

(Für UTF-8 verwenden Sie stattdessen 'StandardCharsets.UTF_8', dann müssen Sie' UnsupportedEncodingException' nicht abfangen, da die Standard-Zeichensätze immer mit der JRE verteilt werden.) –

+0

Nett. War dieser Klasse nicht bewusst. Aktualisiert. Vielen Dank. – aioobe

+0

Ich lese die Quelle der String-Klasse und es hat definitiv nichts mit Zeichensätzen zu tun (checkBounds wird aufgerufen, bevor versucht wird, die Bytes in Zeichen umzuwandeln). –

Verwandte Themen