1. Pinned cluster란?

Java heap에 있는 object들은 일반적으로 이동이 가능하다. 즉, Garbage Collector가 heap을 정리할 때 움직일 수 있다는 것이다. 하지만, 일부 object들은 영구적이거나 또는 일시적으로도 움직일 수 없다. 이렇게 이동이 불가능한 object들을 pinned object라 한다.


2. kCluster, pCluster

2-1. kCluster

Gabage Collector는 heap의 제일 아래쪽에 첫번째 object로 kCluster를 할당한다. kCluster는 오직 class blocks를 위해서만 쓰이는 저장공간이다. 각 class block의 크기는 256 bytes long type인데, kCluster에는 1280개의 class block이 저장될 수 있다. (Each class block is approximately 300 bytes long for a 32-bit SDK and approximately 560 bytes long for a 64-bit SDK)

2-2. pCluster

Garbage Collector가 두번째로 heap에 할당하는 object는 pCluster이다. pCluster는 pinned object들을 위한 저장공간으로 쓰인다. 그 크기는 16 KB long type이다. (pCluster? or pinned object?)

2-3. 문제점 및 해결책

kCluster가 꽉차면, Garbage Collector는 class blocks를 pCluster에 할당한다. pCluster가 꽉차면, 2 KB의 새로운 pClusger를 할당한다. 이 새로운 pCluster는 어느 곳이나 위치할 수 있기 때문에 문제를 야기할 수 있다.

이러한 문제들을 해결하기 위해, pinnedFreeList는 pCluster를 할당하는 방식을 변경한다. 그 방법은 매번의 gc 수행 후, Garbage Collector가 free list의 아래부분(bottom of heap) 중 일정량의 저장공간을 확보하여 pinnedFreeList에 연결한다. 일반적인 메모리 할당 요청이 free list가 쓰이는 반면, pClusters에 대한 할당 요청은 pinnedFreeList가 쓰인다. free list가 모두 소진되면 Garbage Collector는 allocation failure를 발생시키고, gc를 수행한다. 이런 방식으로 모든 pCluster를 heap의 가용한 가장 아래쪽 자리에 할당한다.

3. Garbage Collector

Garbage Collector는 pinnedFreeList에 사용할 공간을 결정하기 위해 아래의 알고리즘을 쓴다.

  • 초기 할당값은 50 KB이다.
  • 초기값이 50 KB가 아니고 pinnedFreeList가 비어있으면, Garbage Collector는 50 KB 또는 마지막 gc가 수행된 이후 cluster로부터 할당된 양의 5배 중 더 큰 크기를 할당한다. (five times the amount of allocations)
  • 초기값이 50 KB가 아니고 pinnedFreeList가 비어있지 않으면, Garbage Collector는 2 KB 또는 마지막 gc가 수행된 이후 cluster로부터 할당된 양의 5배 중 더 큰 크기를 할당한다. (five times amount of allocations)

이 알고리즘은 application이 많은 classes를 로딩할 때 가용한 저장공간을 늘려준다. 따라서 pinnedFreeList의 소진으로 인한 allocation failure를 피할 수 있다. 또한, pinned clusters 할당 크기가 작을 때에는 pinnedFreeList가 사용하는 저장공간의 크기도 줄기 때문에, free list에서 많은 양의 저장공간을 가져가지 않아도 된다.

4. buildPinnedFreeList

buildPinnedFreeList 기능은 위의 알고리즘을 이용하여 pinnedFreeList를 생성한다. 이 기능은 다음의 경우에 쓰인다.

  • 초기 클러스터 (in initializeClusters)
  • heap 확장 끝에서 (At the end of expandHeap)
  • gc0_locked(free, clear_soft_refs) 끝에서 (At the end of gc0_locked)

5. nextPinnedCluster

Garbage Collector가 pinnedFreeList에서 할당 공간을 가져오기 위해 nextPinnedCluster 기능을 이용한다. 이 기능은 nextTLH가 수행하는 방식과 유사하게 동작한다. 즉, pinnedFreeList에서 가용한 free chunk를 가져온다. 만약, pinnedFreeList가 비어있으면, manageAllocFailure를 호출한다.

realObjCAlloc에서는, clusters에 공간이 없으면, Garbage Collector는 새로운 pCluster를 할당하기 위해 nextPinnedCluster를 호출한다.

initializeClusters에서는 Garbage Collector가 nextPinnedCluster를 호출하여 50 KB의 초기 pCluster를 할당하는데 이런 이유는 pinnedFreeList에 있는 유일한 free chunk 크기가 50 KB이기 때문이다. free chunk가 이 크기인 이유는 pinnedFreeList가 초기값으로 50 KB이기 때문이다.

* pinnedFreeList empty : pinnedFreeList가 없거나, pinnedFreeList에서 가용한 리스트가 없음

6. Avoiding fragmentation

For a large Java™ application, such as WebSphere® Application Server, the default kCluster space (for an introduction to kCluster, see Pinned clusters) might not be sufficient to allocate all classblocks. Use the -Xk and -Xp command-line options to specify kCluster and pCluster sizes. For example:

where nnnn specifies the maximum number of classes the kCluster will contain. -Xkinstructs the JVM to allocate space for nnnn class blocks in kCluster. If nnnn is less than 1280, the JVM ignores -Xk and allocates space for 1280 class blocks in kCluster.

GC trace data obtained by setting -Dibm.dg.trc.print=st_verify (for more information about GC tracing, see Tracing) provides a guide for the optimum value of the nnnn parameter. For example::

<GC(VFY-SUM): pinned=4265(classes=3955/freeclasses=0)
dosed=10388 movable=1233792 free=5658>
The 'pinned/classes' size is about the correct size needed for the -Xk parameter. You are recommended to add 10% to the reported value (3955). So, in this example, -Xk4200 would be a good setting.

The difference between pinned (=4265) and classes (=3955) provides a guide for the initial size of pCluster, although because each object might be different in size it is hard to predict the requirements for the pCluster and pCluster overflow options.

You can specify the pCluster and pCluster overflow sizes by the -Xp command-line option:

-Xp<initial cluster size>[,<overflow cluster size>]
where <initial cluster size> specifies the size of the initial pCluster in bytes and <overflow cluster size> optionally specifies the size of overflow (subsequent) pClusters in bytes. You can use the K and M suffixes to set the -Xp arguments in Kilobytes and Megabytes, for example:

-Xp16K,2K sets an initial pCluster of 16 Kilobytes and an overflow of 2 kilobytes, which are the default pCluster sizes.
-Xp1M sets an initial pCluster of 1 Megabyte, with the default overflow of 2 Kilobytes.
-Xp1024K sets an initial pCluster of 1024Kilobytes, with the default overflow of 2 Kilobytes.
Where your application suffers from heap fragmentation, use GC trace and specify the -Xk option. If the problem persists, experiment with higher initial pCluster settings and overflow pCluster sizes.

Note that the -Xp command-line option is available only on the AIX® platform with the subpool GC policy enabled. On other platforms and with other GC policies, this option is ignored.