OOM w Jetty z powodu zbyt dużej pamięci podręcznej zasobów (org.mortbay.jetty.ResourceCache$Content)

Niedawno zaczęliśmy wykorzystywać Jetty do hostowania repozytoriów P2. Szybko okazało się, że dotychczasowy rozmiar sterty który jak się wydawało w zupełności wystarczał do udostępniania statycznych zasobów (-Xmx256M) okazał się niewystarczający – podczas materializacji produktu P2 z repozytorium proces Jetty kończył się wyjątkiem java.lang.OutOfMemoryError. Doraźnym rozwiązaniem było podwojenie XMX, ale w końcu zrobiony automatycznie zrzut pamięci doczekał się analizy. Analiza to zresztą za dużo powiedziane, bo nigdy jeszcze nie widziałem tak ewidentnej przyczyny – po otwarciu zrzutu pamięci w Eclipse Memory Analyzer (MAT) raport Leak Suspects okazał się aż nadto jednoznaczny.

jetty_oom_leak_suspects

Co się stało? Okazuje się, że domyślne wartości w klasie org.mortbay.jetty.ResourceCache są bardzo konserwatywne

// jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java
    private int _maxCachedFileSize =4*1024*1024;
    private int _maxCachedFiles=2048;
    private int _maxCacheSize =32*1024*1024;

ale te w w bazowej konfiguracji domyślnego servletu już nie

   <init-param>
      <param-name>maxCacheSize</param-name>
      <param-value>256000000</param-value>
    </init-param>
    <init-param>
      <param-name>maxCachedFileSize</param-name>
      <param-value>200000000</param-value>
    </init-param>
    <init-param>
      <param-name>maxCachedFiles</param-name>
      <param-value>2048</param-value>
    </init-param>

Spodziewałbym się tutaj chociaż szczątkowej heurystyki – przeznaczenie 256000000 bajtów na pamięć podręczną gdy całkowity rozmiar stery jest niewiele większy (lub mniejszy) nie jest zbyt rozsądną decyzją. Trzymanie w pamięci 200M plików też wydaje się nieco dziwne. Rozwiązaniem jest ustawienie parametru maxCacheSize w WEB-INF/web.xml na wartość o tyle mniejszą od XMX by wystarczyło pamięci do normalnej pracy aplikacji

    <servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.mortbay.jetty.servlet.DefaultServlet</servlet-class>
    <init-param>
      <param-name>maxCacheSize</param-name>
      <!-- 128M - wartość MUSI być mniejsza od XMX -->
      <param-value>134217728</param-value>
    </init-param>
    <init-param>
      <param-name>maxCachedFileSize</param-name>
      <!-- Nie umieszczaj w pamięci podręcznej plików większych niż 32M -->	  
      <param-value>33554432</param-value>
    </init-param>
   </servlet>

Wartość 32M jest empiryczna, przed jej dobraniem sprawdziłem rozmiar największych plików JAR w repozytorium poleceniem (Cygwin is Fun in Terminal)

$ find plugins -name "*.jar"  -type f | xargs ls -lhS | head -n 10

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s