JVM zuŻywa więcej pamięci niz ma przydzielone

0

Witam,
aktualnie męcze się trochę z problemem jak w temacie dla ustawień pamięci "-Xms4000m -Xmx4000m -XX:MetaspaceSize=800M -XX:MaxMetaspaceSize=800M" proces wildfly na Oracle JDK 8.121 za pomocą komendy top(linux) zużywa 7.3GB. Ilość wątków 400 więc nawet 400 x 1MB (Xss Linux) powinno wyjść około 5.2 GB (4000MB+800MB+400MB), a nie 7.3. Heap dump zawsze jest poniżej 4GB więc nie pokazuje tej chorej sytuacji

Jak to u was wygląda??? Jak wytropić co tam siedzi???

0

Ja bym zaczął od mapy pamięci procesu JVM:

Linux: pmap pidProcesu

Windows: VMMap (google: vmmap sysinternals)

Ewentualnie:
jcmd <pid> VM.native_memory summary

2

Te ustawienia dotyczą tylko pamięci dostępnej dla JVMa a nie pamięci JVMa jako takiej. Poza tym linux ładuje dużo współdzielonych libek które też są tam "liczone", mimo ze nie są ładowane bezpośrednio jako przstrzeń aplikacji.

0
Szczery napisał(a):

Witam,
aktualnie męcze się trochę z problemem jak w temacie dla ustawień pamięci "-Xms4000m -Xmx4000m -XX:MetaspaceSize=800M -XX:MaxMetaspaceSize=800M" proces wildfly na Oracle JDK 8.121 za pomocą komendy top(linux) zużywa 7.3GB. Ilość wątków 400 więc nawet 400 x 1MB (Xss Linux) powinno wyjść około 5.2 GB (4000MB+800MB+400MB), a nie 7.3. Heap dump zawsze jest poniżej 4GB więc nie pokazuje tej chorej sytuacji

Jak to u was wygląda??? Jak wytropić co tam siedzi???

Co do tych 7.3GB pamieci - to z ktorej kolumny top-a bierzesz ta wartosc? z VIRT czy z RES? Jesli bierzesz to z VIRT to to nie jest realne zuzycie, bo realne zuzycie pokazuje wlasnie RES.

1

Biorę z RES w VIRT mam 15GB :-). Dzisiaj uruchomiłem aplikację z przełącznikiem -XX:NativeMemoryTracking=summary wyznaczyłem BaseLine na poziomie kiedy JVM zajmuje 5.2 GB w top i czekamy do godziny pewnie tak 14 aż dojdzie znów do 7GB i zobacze za pomocą jcmd pid VM.native_memory summary.diff co tak przyrosło

0

Poniżej efekty** jcmd pid VM.native_memory**, aktualnie nie udało się jeszcze dojśc do 7.3 GB stoimy na 6.7GB co jest i tak o 1.5GB za dużo, ale jak się dowiedziełm nadgorliwy admin zrobił update JDK z 121 na 171 może to ma znaczenia.
Na podstawie poniższych danych niepokoi mnie rozmiar class/metaspace(reserved=1480683KB) to aż 1.5GB pamięci zarezerowowanej za pomocą mmap (natywnie) - dlaczego???!!! przecież -XX:MetaspaceSize=800M -XX:MaxMetaspaceSize=800M a dodtakowo widać wartość użycia (committed=490987KB) na poziomie 490MB

Native Memory Tracking:

Total: reserved=6778143KB, committed=5754387KB
   - Java Heap (reserved=4096000KB, committed=4096000KB)
                        (mmap: reserved=4096000KB, committed=4096000KB)

  - Class (reserved=1480683KB, committed=490987KB)
              (classes #73041)
              (malloc=18411KB #183362)
              (mmap: reserved=1462272KB, committed=472576KB)

- Thread (reserved=459441KB, committed=459441KB)
               (thread #445)
               (stack: reserved=457456KB, committed=457456KB)
               (malloc=1464KB #2240)
               (arena=521KB #877)

- Code (reserved=294552KB, committed=260492KB)
            (malloc=44952KB #38637)
            (mmap: reserved=249600KB, committed=215540KB)

- GC (reserved=52046KB, committed=52046KB)
         (malloc=38038KB #8551)
         (mmap: reserved=14008KB, committed=14008KB)

- Compiler (reserved=1737KB, committed=1737KB)
                 (malloc=1606KB #4871)
                 (arena=131KB #15)

- Internal (reserved=207018KB, committed=207018KB)
               (malloc=206986KB #750091)
               (mmap: reserved=32KB, committed=32KB)

- Symbol (reserved=76318KB, committed=76318KB)
               (malloc=73113KB #733223)
               (arena=3205KB #1)

- Native Memory Tracking (reserved=26995KB, committed=26995KB)
                                          (malloc=74KB #863)
                                          (tracking overhead=26920KB)

- Arena Chunk (reserved=1830KB, committed=1830KB)
                        (malloc=1830KB)

- Unknown (reserved=81524KB, committed=81524KB)
                  (mmap: reserved=81524KB, committed=81524KB
0

Możliwe, że masz (mialeś) dużo tworzonych tymczasowych klas, proxy (Spring i JavaEE) tak potrafią, aczkolwiek naprawdę duże ilości to sa tworzone przez technologie typu JSP, toole do raportow itp. Tu bym szukał. Opcje -XX:+TraceClassLoading --XX:+TraceClassUnloading powinny to pokazać.

0

Na pokładzie ostro uzywamy Grooviego, JasperReports, niestety Axis 1 + 2. Więc jest troche technologi które potrfią dynamicznie potworzyć klasy. Jednak z monitoringu(newrelic) nie widać aby metaspace miał tendencje zwyżkowe cały czas trzyma się na około 500MB. Więc zaskakująca jest ta wartość 1.5 GB znalazłem https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/considerations.html, i wpis od Class Metadata że The size of the region can be set with CompressedClassSpaceSize and is 1 gigabyte (GB) by default. Więc kolejnym krokiem będzie wykorzystanie parametru CompressedClassSpaceSize

0

Kolejna ciekawostka
top:
screenshot-20180705145109.png

i komenda jcmd 43615 VM.native_memory
screenshot-20180705145231.png

Gdzie widać, że z punktu widzenia JVM zajmuje on 6.8 GB (1 GB zarezerwowany na przestrzeń Class a wykorzystany 500MB), a z punktu widzenia systemu zajmuje 7.7GB

Czyli aktualnie JVM wpierdziela niepotrzebnie 1GB więcej no i gdzie się jeszcze podział kolejny 1GB....oddajcie mi moje 2GB złodzieje

0

@Szczery: o_O ty żartujesz? Pisałem wyżej, czym innym jest heap dostępny dla APLIKACJI a czym innym jest JVM jako taki. JVM sam z siebie jest aplikacją, która zajmuje się interpretacją, kompilacją, optymaliacją i uruchamianiem javoweogo bajtkodu i też potrzebuje pamięć do działania. Ta pamięć nie liczy się na poczet heapu.

0

A ciekawe czy to śledzi pamięć zaalokowaną ręcznie poza stertą przez aplikację? Tj. wszelkie DirectByteBuffer?

0
Krolik napisał(a):

A ciekawe czy to śledzi pamięć zaalokowaną ręcznie poza stertą przez aplikację? Tj. wszelkie DirectByteBuffer?

Wydaje mi się, że VM.native_memory tego nie robi, można spojrzeć tak:

  1. Wyprodukować plik słusznego rozmiaru (np. 768MB), tak by było co mapować i było to w miarę zauważalne, słowem, z rozmachem.
dd if=/dev/zero of=blahz.dat bs=1M  count=768
  1. Wielokrotnie zammapować ten plik używając prostego testu:
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

class Foo {

  public static void main(String[] args) throws Exception {
      if (args.length != 3) {
          System.out.println("Usage : Foo <#iterations> <segment size (in bytes)> <input file name>");
      } else {
          int nIter = Integer.valueOf(args[0]);
          int nSize = Integer.valueOf(args[1]);
          String inputFileName = args[2];

          System.out.printf("MMAP iterations = %d\nsegment size = %d\nInput filename = %s\n", nIter, nSize, inputFileName);

          MappedByteBuffer[] ref = new MappedByteBuffer[nIter];
          for (int i = 0; i < nIter; i++)
              ref[i] = new RandomAccessFile(inputFileName, "r").getChannel().map(FileChannel.MapMode.READ_ONLY, 0, nSize);

          System.out.println("Press return to exit");
          System.console().readLine();
      }
  }
}
  1. Uruchomić test case (uruchamiam 2, żeby było widać różnicę via : pmap i jcmd VM.native_summary). Rozmiar mmapowanego segmentu=666MB i dwa przebiegy: 10 iteracji i 100 iteracji mmapa (co daje ~6.5GB i ~65GB spodziewanej różnicy).

Dla 10 iteracji:

(Tu korzystam z dobrodziejstw basha $(()) , żeby nie klepać ręcznie tych 666 MB w bajtach)

[pkw@pkwcent ~]$ javac Foo.java
[pkw@pkwcent ~]$ java -XX:NativeMemoryTracking=summary Foo 10 $((666*1024*1024)) blahz.dat 
MMAP iterations = 10
segment size = 698351616
Input filename = blahz.dat
Press return to exit

('Press return', to żeby proces powisiał w powietrzu, taki oczywizm, ale może nie dla każdego ;-) )

  1. W innej sesji podsumowanie via pmap:
[pkw@pkwcent ~]$ pmap -x `jps | grep Foo | awk '{print $1}'` | grep -i total | awk '{print $3/1024/1024 " in GB"}'
9.33921 in GB

oraz via VM.native_memory

[pkw@pkwcent ~]$ jcmd `jps | grep Foo | awk '{print $1}'` VM.native_memory | grep Total | sed 's/KB.*//g' | awk -F\= '{print $2/1024/1024 " in GB"}'
2.18665 in GB

PMAP : 9.33921 in GB
JCMD : 2.18665 in GB

Gołym okiem widać, że VM.native_memory omija niektóre segmenty.

  1. Dla 100 iteracji mmap.
[pkw@pkwcent ~]$ java -XX:NativeMemoryTracking=summary Foo 100 $((666*1024*1024)) blahz.dat 
MMAP iterations = 100
segment size = 698351616
Input filename = blahz.dat
Press return to exit

PMAP : 67.8754 in GB
JCMD : 2.18667 in GB

Morał: PMAP pokazuje te mmapowane segmenty, zaś VM.native_memory wydaje się je olewać.

0

A u mnie
JCMD : 6.7 GB
PMAP :14.6596 in GB
screenshot-20180710083035.png

A pamięć dostępna dla maszyny 10 GB

1 użytkowników online, w tym zalogowanych: 0, gości: 1