목차

Java Memory Analysis

기본 Heap 메모리 설정

Default 값

# java 7 이하
java -XX:+PrintFlagsFinal -version 2>&1 | grep -i -E 'heapsize|permsize|version'
# java 8 이상
java -XX:+PrintFlagsFinal -version 2>&1 | grep -i -E 'heapsize|metaspace|version'
 
uintx InitialHeapSize                          := 522190848                           {product}
uintx MaxHeapSize                              := 8355053568                          {product}
System.out.println(Runtime.getRuntime().maxMemory());

64Bit 운영체제에서 포인터 크기

Heap Dump on OutOfMemoryError

jmap

jhat

MAT

용어

IBM HeapAnalyzer

HPJmeter

jstat

현재 JVM의 메모리 상태를 확인해 볼 수 있다.

옵션명 내용
class 클래스 로더의 동작에 관한 통계 데이터
compiler HotSpot Just-in-Time 컴파일러의 동작에 관한 통계 데이터
gc GC된 heap의 동작에 관한 통계 데이터
gccapactiy 세대마다의 용량과 대응하는 영역에 관한 통계 데이터
gccause GC 통계 데이터의 개요(-gcutil 와 같다)와 직전 및 현재 (적용 가능한 경우)의 GC이벤트의 원인
gcnew New 세대의 동작에 관한 통계 데이터
gcnewcapacity New 세대의 사이즈와 대응하는 영역에 관한 통계 데이터
gcold Old 세대 및 Permanent 세대의 동작에 관한 통계 데이터
gcoldcapacity Old 세대의 사이즈에 관한 통계 데이터
gcpermcapacity Permanent 세대의 사이즈에 관한 통계 데이터
gcutil GC 통계 데이터의 개요
printcompilation HotSpot 컴파일 방법의 통계 데이터

SSH로 특정 서버의 GC 상태보기

서버가 여러대일 경우 특정 서버에 자동 접속하여 해당 서버의 Tomcat 인스턴스를 찾아서 gcutil 실행

ssh myhostname 'bash -s' <<'ENDSSH'
jstat -gcutil `jps | grep Bootstrap | awk '{print $1}'` 1s
ENDSSH

Code로 heap dump 뜨기

import javax.management.MBeanServer;
import java.lang.management.ManagementFactory;
 
import com.sun.management.HotSpotDiagnosticMXBean;
 
/**
 * 현재 Java Application의 Heap Dump를 뜨는 함수
 * @see <a href="https://blogs.oracle.com/sundararajan/programmatically-dumping-heap-from-java-applications">Programmatically dumping heap from Java applications</a>
 */
public class HeapDumper {
    // This is the name of the HotSpot Diagnostic MBean
    private static final String HOTSPOT_BEAN_NAME =
        "com.sun.management:type=HotSpotDiagnostic";
    // field to store the hotspot diagnostic MBean
    private static volatile HotSpotDiagnosticMXBean hotspotMBean;
 
    /**
     * Call this method from your application whenever you
     * want to dump the heap snapshot into a file.
     *
     * @param fileName name of the heap dump file
     * @param live     flag that tells whether to dump
     *                 only the live objects
     */
    public static void dumpHeap(String fileName, boolean live) {
        // initialize hotspot diagnostic MBean
        initHotspotMBean();
        try {
            hotspotMBean.dumpHeap(fileName, live);
        } catch (RuntimeException re) {
            throw re;
        } catch (Exception exp) {
            throw new RuntimeException(exp);
        }
    }
 
    // initialize the hotspot diagnostic MBean field
    private static void initHotspotMBean() {
        if (hotspotMBean == null) {
            synchronized (HeapDumper.class) {
                if (hotspotMBean == null) {
                    hotspotMBean = getHotspotMBean();
                }
            }
        }
    }
 
    // get the hotspot diagnostic MBean from the
    // platform MBean server
    private static HotSpotDiagnosticMXBean getHotspotMBean() {
        try {
            MBeanServer server = ManagementFactory.getPlatformMBeanServer();
            HotSpotDiagnosticMXBean bean =
                ManagementFactory.newPlatformMXBeanProxy(server,
                    HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean.class);
            return bean;
        } catch (RuntimeException re) {
            throw re;
        } catch (Exception exp) {
            throw new RuntimeException(exp);
        }
    }
 
    public static void main(String[] args) {
        // default heap dump file name
        String fileName = "heap.hprof";
        // by default dump only the live objects
        boolean live = true;
        // simple command line options
        switch (args.length) {
            case 2:
                live = args[1].equals("true");
            case 1:
                fileName = args[0];
        }
        // dump the heap
        dumpHeap(fileName, live);
    }
}