2015-05-11 9 views
8

Niedawno widziałem dziwne zachowanie w mojej aplikacji, którego tak naprawdę nie potrafię wyjaśnić. Występują bardzo rzadko, więc nie mogę ich odtworzyć. Podczas gdy miejsce, w którym występują te problemy, zmienia się, wspólną częścią wydaje się być to, że tablica zmienia rozmiar po utworzeniu (wiem, to nie jest możliwe, stąd: dziwne zachowanie).zmiany długości tablicy w openjdk

Kilka przykładów, aby mój punkt jasne:

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) 

kod, który spowoduje to:

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

więc najpierw sprawdzić, czy bufor jest wystarczająco duży (więcej niż 86 bajty) przed próbą utworzenia łańcucha od nich.

Drugi przykład:

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) 

Linia, która powoduje, że ten wyjątek jest:

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

musiałem spojrzeć na openjdk źródła String.java, ale nie mógł znaleźć błędu chyba tablice mogły nagle zacząć zmieniać rozmiar po utworzeniu.

Jedyne odniesienie, które można znaleźć w Internecie, może być związane z błędem openjdk: https://bugs.openjdk.java.net/browse/JDK-6817012. Ten błąd został oznaczony jako "nie problem", chociaż podczas czytania tego nie mogę powiedzieć, czy wspomniany problem nie został rozpoznany jako błąd, czy też osoba, która zamknęła błąd, nie widzi powodu, dla którego ten błąd spowodowałoby problemy.

Jeśli ktoś kiedykolwiek napotkał podobny problem, byłbym bardzo wdzięczny, gdyby o tym usłyszał. W obecnej wersji problem jest zbyt niestabilny, aby spróbować go naprawić, używając innych wersji openjdk.

Problem był widziany:

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

Używasz Java 6. Java 7 prostu osiągnął kres życia. Naprawdę powinieneś zaktualizować swoją Javę. – icza

+3

Drugi przykład można łatwo wyjaśnić, jeśli znak nie pojawia się w łańcuchu. W takim przypadku lastIndexOf zwraca -1, a skarga dotyczy użycia indeksu -1. –

+0

Zalecam również uaktualnienie Java do 8, jeśli to możliwe. A najlepiej wersję Oracle. OpenJDK dał mi tylko bóle głowy. –

Odpowiedz

3

Tworzycie nowy String użyciu byte[] tablicę bez podania Charset. Tak więc domyślam się, że domyślny zestaw znaków systemowych został zmieniony i widać zmiany zachowania. Sugerowałbym, aby zawsze wyraźnie określać zestaw znaków. Na przykład:

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

Sprawdziliśmy tę możliwość. System jest w większości przeznaczony tylko do odczytu, więc domyślny zestaw znaków nie mógł zostać zmieniony. Co więcej, gdyby to się zmieniło, problem byłby widoczny w wielu miejscach, widzieliśmy tylko jedno wystąpienie takiego wyjątku podczas całego przebiegu. Wreszcie, metoda checkBounds w java.lang.String wydaje się sprawdzać wyłącznie na podstawie rozmiaru tablicy bajtów, nie bierze pod uwagę zestawu znaków. –

+0

Zestaw znaków mógł się nie zmienić, ale być może dane wejściowe do systemu, który to spowodował, nie pojawiły się zbyt często? – aioobe

+0

Wejście jest wyzwalane z grubsza 4 razy na sekundę dla tego konkretnego wątku. Inne wątki są uruchamiane jeszcze częściej. –

4

Jest to najprawdopodobniej problem związany z bajtami i zestawem znaków systemowych. The documentation wyraźnie mówi:

Zachowanie tego konstruktora, gdy podane bajtów nie obowiązują w domyślnym kodowaniem jest nieokreślony.

Można obejść ten jawnie zapewniając poprawną charset:

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

(Dla UTF-8 użyj zamiast tego 'StandardCharsets.UTF_8', wtedy nie musisz wychwytywać' UnsupportedEncodingException', ponieważ standardowe zestawy znaków zawsze są dystrybuowane z JRE.) –

+0

Nice. Nie wiedziałem o tej klasie. Zaktualizowano. Dzięki. – aioobe

+0

Przeczytałem źródło klasy String i zdecydowanie nie ma to nic wspólnego z zestawami znaków (checkBounds jest wywoływane przed próbą konwersji bajtów na znaki). –

Powiązane problemy