java jvm and gc

jvisualvm截图

Heap and Non-Heap Memory

The JVM memory consists of the following segments:

  1. Heap Memory, which is the storage for Java objects
  2. Non-Heap Memory, which is used by Java to store loaded classes and other meta-data
  3. JVM code itself, JVM internal structures, loaded profiler agent code and data, etc.

Heap

The JVM has a heap that is the runtime data area from which memory for all class instances and arrays are allocated. It is created at the JVM start-up.

Used heap memory consists of live and dead objects.

  1. Live objects are accessible by the application and will not be a subject of garbage collection.
  2. Dead objects are those which will never be accessible by the application but have not been collected yet by the garbage collector. Such objects occupy the heap memory space until they are eventually collected by the garbage collector.

The heap size may be configured with the following VM options:

  1. -Xmx<size> - to set the maximum Java heap size
  2. -Xms<size> - to set the initial Java heap size

By default, the maximum heap size is 64 Mb.

Heap memory for objects is reclaimed by an automatic memory management system which is known as a garbage collector. The heap may be of a fixed size or may be expanded and shrunk, depending on the garbage collector's strategy.

Non-Heap

Also, the JVM has memory other than the heap, referred to as non-heap memory. It is created at the JVM startup and stores per-class structures such as runtime constant pool, field and method data, and the code for methods and constructors, as well as interned Strings.

Unfortunately, the only information JVM provides on non-heap memory is its overall size. No detailed information on non-heap memory content is available.

The abnormal growth of non-heap memory size may indicate a potential problem, in this case you may check up the following:

  1. If there are class loading issues such as leaked loaders. In this case, the problem may be solved with the help of Class loaders view.
  2. If there are strings being massively interned. For detection of such problem, Object allocation recording may be used.

If the application indeed needs that much of non-heap memory and the default maximum size of 64 Mb is not enough, you may enlarge the maximum size with the help of -XX:MaxPermSize VM option. For example, -XX:MaxPermSize=128m sets the size of 128 Mb.

Heap组成部分说明

  1. Heap区分两大块,一块是young generation,另一块是old generation。上图中的permanent generation不属于Heap。
  2. 在young generation中,有一个叫eden的空间,主要是用来存放新生的对象,还有两个survivor spaces(from, to),即部分示例图中的s0和s1,它们的大小总是一样,它们用来存放每次垃圾回收后存活下来的对象。
  3. 在old generation中,主要存放应用程序中生命周期长的内存对象。
  4. 在young generation块中,垃圾回收一般用copying的算法,速度快。每次gc的时候,存活下来的对象首先由eden拷贝到某个survivor space,当survivor space空间满了后,剩下的live对象就被直接拷贝到old generation中去。因此,每次gc后,eden内存块会被清空。
  5. 在old generation块中,垃圾回收一般用mark-compact的算法,速度慢些,但减少内存要求。
  6. 垃圾回收分多级,0级为全部(full)的垃圾回收,会回收old段中的垃圾,1级或以上为部分垃圾回收,只会回收new中的垃圾,内存溢出通常发生于old段或perm段垃圾回收后,仍然无内存空间容纳新的java对象的情况。

JVM内存申请过程

  1. jvm会试图为相关java对象在eden中初始化一块内存区域。
  2. 当eden空间足够时,内存申请结束;否则到下一步。
  3. JVM试图释放在eden中所有不活跃的对象(这属于1或更高级的垃圾回收),释放后若eden空间仍然不足以放入新对象,则试图将部分eden中活跃对象放入survivor区。
  4. survivor区被用来作为eden及old的中间交换区域,当old区空间足够时,survivor区的对象会被移到old区,否则会被保留在survivor区。
  5. 当old区空间不够时,jvm 会在old区进行完全的垃圾收集(0级)。
  6. 完全垃圾收集后,若survivor及old区仍然无法存放从eden复制过来的部分对象,导致jvm无法在eden区为新对象创建内存区域,则出现out of memory错误。

Hotspot Architecture

The main components of the JVM include the classloader, the runtime data areas, and the execution engine.

Key Hotspot Components

There are three components of the JVM that are focused on when tuning performance. The heap is where your object data is stored. This area is then managed by the garbage collector selected at startup. Most tuning options relate to sizing the heap and choosing the most appropriate garbage collector for your situation. The JIT compiler also has a big impact on performance but rarely requires tuning with the newer versions of the JVM.

Describing Garbage Collection

In a programming language like C, allocating and deallocating memory is a manual process. In Java, process of deallocating memory is handled automatically by the garbage collector. The basic process can be described as follows.

Step 1: Marking

The first step in the process is called marking. This is where the garbage collector identifies which pieces of memory are in use and which are not.

Referenced objects are shown in blue. Unreferenced objects are shown in gold. All objects are scanned in the marking phase to make this determination. This can be a very time consuming process if all objects in a system must be scanned.

Step 2: Normal Deletion

Normal deletion removes unreferenced objects leaving referenced objects and pointers to free space.

The memory allocator holds references to blocks of free space where new object can be allocated.

Step 2a: Deletion with Compacting

To further improve performance, in addition to deleting unreferenced objects, you can also compact the remaining referenced objects. By moving referenced object together, this makes new memory allocation much easier and faster.

JVM Generations

The information learned from the object allocation behavior can be used to enhance the performance of the JVM. Therefore, the heap is broken up into smaller parts or generations. The heap parts are: Young Generation, Old or Tenured Generation, and Permanent Generation.

The Generational Garbage Collection Process

Now that you understand why the heap is separted into different generations, it is time to look at how exactly these spaces interact. The pictures that follow walks through the object allocation and aging process in the JVM.

object allocation in eden

First, any new objects are allocated to the eden space. Both survivor spaces start out empty.

minor gc after eden filling up

When the eden space fills up, a minor garbage collection is triggered.

copy reference objects to s0

Referenced objects are moved to the first survivor space. Unreferenced objects are deleted when the eden space is cleared.

object increment age and copy to s1

At the next minor GC, the same thing happens for the eden space. Unreferenced objects are deleted and referenced objects are moved to a survivor space. However, in this case, they are moved to the second survivor space (S1). In addition, objects from the last minor GC on the first survivor space (S0) have their age incremented and get moved to S1. Once all surviving objects have been moved to S1, both S0 and eden are cleared. Notice we now have differently aged object in the survivor space.

minor gc

At the next minor GC, the same process repeats. However this time the survivor spaces switch. Referenced objects are moved to S0. Surviving objects are aged. Eden and S1 are cleared.

objects promotion

This slide demonstrates promotion. After a minor GC, when aged objects reach a certain age threshold (8 in this example) they are promoted from young generation to old generation.

objects promoted to the old generation space

As minor GCs continue to occure objects will continue to be promoted to the old generation space.

major gc

So that pretty much covers the entire process with the young generation. Eventually, a major GC will be performed on the old generation which cleans up and compacts that space.

JVM architecture示意图

JVM Heap示意图

GC 算法和 GC 日志解读

GC Algorithms: Implementations这篇文章非常优秀,其中也指出是 GC 日志中的报告显示 bug,需要仔细多读几遍。

References

  1. Java Garbage Collection Basics
  2. Java 内存模型及GC原理
  3. JVM Memory Structure
  4. JVM Internals
  5. Garbage Collection
  6. getting started with the G1 garbage collector
  7. GC Algorithms: Implementations