Java Performance, 2nd Edition by Scott Oaks ch7 heap memory, ch8 native memory

Chapter 7. Heap Memory Best Practices

We have two conflicting goals here. The first general rule is to create objects sparingly and to discard them as quickly as possible. Using less memory is the best way to improve the efficiency of the garbage collector. On the other hand, frequently re-creating some kinds of objects can lead to worse overall performance (even if GC performance improves)

この章の趣旨は、memoryとそれを片付けるGCの効率化とシステム全体のパフォーマンスを向上する方法がまとめられてる。

 

Heap Histograms

% jmap -histo process_id

このコマンドでJavaアプリのheapの使用状況がわかる。覚えておこう

使用例

%  jmap -histo 21386

 num     #instances         #bytes  class name
----------------------------------------------
   1:         21019      152664296  [I
   2:         69898       23376176  [B
   3:        152345       18413344  [C
   4:         95700        2296800  java.lang.String
   5:         18177        1599576  java.lang.reflect.Method
   6:         24864        1455320  [Ljava.lang.Object;
   7:         33657        1346280  java.util.LinkedHashMap$Entry
   8:         63296        1316584  [Ljava.lang.Class;
   9:         17730        1230464  [Ljava.util.HashMap$Node;
  10:          9409        1049080  java.lang.Class

I = int

B = byte

C = char

reference : https://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getName()

 

Out-of-Memory Errors

主に原因は3種類

  • Out of native memory 

    • アプリケーション以外の要因で発生する可能性がある。
  • Out of metaspace memory

    • heap外の領域でデフォルトではmaximum sizeは設定されていない。任意にmaximum sizeが設定されている場合にのみ起こりうる。
    • 考えられる原因は二つ、シンプルにクラスパスで定義されているクラスの量が設定されているmaximum metaspace sizeを超えてる。又は、古いClassLoaderによloadされたクラスが残ってしまってメモリーを圧迫する。
  • Out-of-heap memory

    • objectsがGCに回収されるペースがobjectsが作られるスピードに追いつかなくてmemory leak が発生する。

どのケースでもheap dumpもしくはmemory histogramで解析するの有効手段。

 

Reducing Object Size

The size of an object can be decreased by (obviously) reducing the number of instance variables it holds and (less obviously) by reducing the size of those variables. 

 

Object Reuse

objects that are reused stay around for a long time in the heap. If the heap has a lot of objects, there is less room to create new objects, and hence GC operations will occur more frequently.

The length of time it takes to perform a full GC is proportional to the number of objects that are still alive in the old generation.

Objectの再利用によってパフォーマンスが向上するケースは限定的。connection pool やinitializeコストが大きいオブジェクトをpoolingして再利用するのは有効。

オブジェクトの再利用が推奨されない理由は

  1. オブジェクトが長い間Heapを占有するとHeap の利用可能領域が少なくなりGCが走る頻度が高くなる。
  2. オブジェクトがHeapに格納される間は eden -> survivor space -> old generation の順番で時間がたつと違う領域に移される。その領域を移動するプロセスがコスト。
  3. Full GCはalive objectがheapに多く残っている場合の方がパフォーマンスが悪い。

 

Chapter 8. Native Memory Best Practices

If enough physical memory to contain the entire total footprint of an application is not available, performance may begin to suffer.

ここでmayをつかっているのはapplicationがnative memory を多く占有していてもそれらは起動時にのみ必要な.jarが占有していて、それらはvirtual memoryに移されてもperformanceに影響しない可能性があるため。

ちなみにfootprintとはJava processのheap+non heapが占有しているメモリーの量。

 

When we look at performance, only committed memory really matters: a performance problem never results from reserving too much memory.

reserve memory とは特定のプロセスのために確保されているメモリー領域ではなく、必要に応じてOSが振り分けるメモリー領域の最大値。

 

Native Memory Tracking

% jcmd process_id VM.native_memory summary

このコマンドでnative memory の内訳が見れる。

見れるのはheap, Metaspace, thread stacks, GC, Native librariy allocationなどそれぞれのメモリー使用量がわかる。

  • If an application seems to be using too much native memory, it is likely from native libraries rather than the JVM itself.

なるほど〜。