2015-10-21 36 views
18

Pracujemy nad aplikacją biznesową (1 milion + LOC) opracowaną od ponad 10 lat. Podczas przejścia na JDK8 pojawia się problem z metaprzestrzenną JDK8. Wydaje się, że jest to związane z wersją JaxB wymienioną w pliku com.sun.xml.ws:webservices-rt:1.4 (Metro 1.4). Ze względu na intensywne łączenie w aplikacji i tworzenie starszych klas/instancji za pośrednictwem JaxB nie jest łatwo włączyć stare biblioteki w locie.Stare JaxB i JDK8 Metaspace OutOfMemory Issue

Aktualnie badamy ten problem. Stworzyliśmy przykładowy program, który odtwarza to zachowanie:

import java.io.ByteArrayInputStream; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBException; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class X 
{ 
    private static final String XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><x test=\"test\" />"; 

    @XmlAttribute 
    String test; 

    public static void main(String[] args) throws JAXBException, InterruptedException 
    { 
    System.out.println("start"); 

    while (true) 
    { 
     JAXBContext jc = JAXBContext.newInstance(X.class); 
     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     X object = (X) unmarshaller.unmarshal(new ByteArrayInputStream(XML.getBytes())); 
     System.out.println(object.test); 
    } 
    } 
} 

JDK7 utrzymuje czystość PermGenSpace. (Symulowane za pomocą 16M PermGen) Memory of run with JDK7

Przy użyciu JDK8 aplikacja działa wolno do wyjątku OOM. VisualVM przechwytuje wyjątek i utrzymuje proces na maksymalnym dostępnym metaprzestrzeni. Nawet tutaj utknął po dłuższej chwili na maksimum. (Symulowane przy użyciu Metaspace 16M) Memory of run with JDK8

Czy ktoś ma jakieś pomysły na to, jak zachować dotychczasowe zachowanie śmieciarki, abyśmy nie mieli problemów z pamięcią? Czy masz jakieś inne pomysły, jak sobie z tym poradzić?

Dzięki.

Edit1: parametry Run JDK7:

-XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:MaxPermSize=16M -XX:PermSize=1M -XX:+UseParallelOldGC -XX:+HeapDumpOnOutOfMemoryError

=> Brak wysypisk sterty są tworzone

parametry wirowania JDK8:

-XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:MaxMetaspaceSize=16M -XX:MetaspaceSize=1M -XX:+UseParallelOldGC -XX:+HeapDumpOnOutOfMemoryError

=> Zrzuty sterty są generowane podczas pracy.

Dostępna pamięć VisualVM nie pokazuje rzeczywistej maksymalnej wartości metaprzestrzennej. Jeśli nie jest ograniczona, metaprzestrzeń stale rośnie, aż pamięć zostanie przekroczona.

edit 2:

Próbowałem wszystkie dostępne śmieciarze dla JDK8. Wszystkie mają ten sam problem.

edit 3:

Rozwiązywanie przez wymianę bibliotekami jest trudny w naszej rzeczywistej aplikacji z powodu dużego sprzężenia między JAXB & kilku modułów naszej aplikacji. W krótkim okresie potrzebna jest więc poprawka w zakresie działania "śmieciarek". Na dłuższą metę poprawka proppera jest już zaplanowana.

+0

"VisualVM przechwytuje wyjątek i utrzymuje proces" - nigdy nie wiedziałem, że VisualVM może to zrobić. Poza tym, twój zrzut ekranu mówi, że w twoim biegu Java8 Metaspace ma limit "1GB", ale pozostaje na "16 MB", który jest daleki od uruchomienia w kierunku OOME. Metaspace nie wydaje się być zbierany, ale wydaje się, że istnieje prosty, oczywisty powód: w konfiguracji Java 8 * utrzymuje * klasy, ponieważ licznik pozostaje stale w ~ 4300 klasach, podczas gdy w biegu Java 7 , policzono ogromną liczbę ~ 43 000 klas. Tak więc, wydaje się, że klasy są stale odtwarzane ... – Holger

+0

OOM są wyświetlane w debugerze Eclipse podczas działania. Zadanie jest ograniczone parametrami w konfiguracji uruchamiania do 16 MB Metaspace. Nie dotyczy to wystąpienia VisualVM. Więc to mówi inne ilości pamięci. Jeśli zostawiam działającą aplikację bez VisualVM, OOM zatrzymuje proces po prawej stronie w tym samym momencie, w którym proces JDK8 uderza w Metaprzestrzeń 16 MB. Podczas korzystania np. webservices-rt 1.6.1 lub usunięcie tego i przy użyciu implementacji JaxB JDK8 przykładowy program zachowuje stałą ilość 12,5 MB Metasprzestrzeni. Jeśli nie ograniczając pamięci JDK8, wzrośnie, dopóki nie zostanie użyte wszystko. –

+0

Jestem zdezorientowany. Co pokazują zrzuty ekranu? Czy analizujesz swoją aplikację lub VisualVM? – Holger

Odpowiedz

21

Rozwiązaliśmy naszą aktualną kwestię aż stanie naprawić wszystkich wystąpień w naszej aplikacji za pomocą następującego VM-parametr:

-Dcom.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize=true 

Mam nadzieję, że to pomoże innym w podobnych sprawach ...

+0

Mamy również podobny problem związany z OOME, kiedy przełączyliśmy naszą aplikację z JDK7 na JDK8 i ten parametr rozwiązał nasz problem. Dziękujemy za opublikowanie rozwiązania !!! – Rajinder

+1

Dzięki, pomogło. Możesz także umieścić JAXBContext.newInstance poza pętlą (jeśli jest w kodzie) i zachować ją jako singleton. Ponadto błąd został naprawiony za pomocą jaxb-2.1.13 (jira ticket: JAXB-564) – Thierry

+0

Dzięki temu rozwiązano ten sam problem z klientem JAX-WS, który używa JAXB do wiązania danych. –

2

JAXBContext Metoda .newInstance() powinna zostać użyta tylko raz, aby stworzyć kontekst dla twojej klasy, aby unmarshall. W przeciwnym razie wykorzysta to twoją permgen lub metaprzestrzeń.