문서의 선택한 두 판 사이의 차이를 보여줍니다.
양쪽 이전 판 이전 판 다음 판 | 이전 판 다음 판 양쪽 다음 판 | ||
java:memory [2015/07/02 18:00] kwon37xi [jmap] |
java:memory [2022/01/26 14:41] kwon37xi [기본 Heap 메모리 설정] |
||
---|---|---|---|
줄 2: | 줄 2: | ||
* [[java: | * [[java: | ||
* [[java: | * [[java: | ||
+ | * [[java: | ||
+ | * [[java: | ||
+ | * [[java: | ||
* [[http:// | * [[http:// | ||
+ | |||
+ | ===== 기본 Heap 메모리 설정 ===== | ||
+ | * https:// | ||
+ | * 장비 메모리에서 OS와 다른 애플리케이션이 사용하는 것을 제외하고 설정할 수 있다.(보통 2GB정도 남겨두고 나머지를 설정하면 될듯) | ||
+ | * 하지만 Lucene의 경우 off heap 메모리를 사용하기 때문에 ElasticSearch는 장비 메모리의 50%만 heap으로 설정함. off heap 사용시에 관련 사항 주의. | ||
+ | * 운영체제 메모리가 아무리 많아도 heap은 32GB를 넘기지는 않게 한다. 31GB 정도 추천 | ||
+ | * Linux 운영체제 swap 일어나는 것을 방지하기 위해 **swappiness=1** 로 조정한다. [[linux: | ||
+ | |||
+ | ===== Default 값 ===== | ||
+ | * 운영체제에 따라 Java 버전에 따라 기본 메모리 설정이 다를 수 있다. 아래 명령으로 확인 가능하다. | ||
+ | <code sh> | ||
+ | java -XX: | ||
+ | </ | ||
+ | * 혹은 Java 애플리케이션에서 확인도 가능하다. | ||
+ | <code java> | ||
+ | System.out.println(Runtime.getRuntime().maxMemory()); | ||
+ | </ | ||
+ | </ | ||
+ | ===== 64Bit 운영체제에서 포인터 크기 ===== | ||
+ | * 64Bit 운영체제에서라도 64bit long이 아니라 기본적으로 32bit 포인터를 사용한다. | ||
+ | * 그러나 Heap 사이즈가 **대략 32GB**가 넘어가면 그때부터 64bit 포인터로 바뀐다. 이렇게 되면 포인터 자체가 차지하는 메모리가 너무 커서 낭비적이 될 수 있다. | ||
+ | * 일반적으로 Heap Size가 31GB 정도일 때 32bit 압축 포인터가 거의 확실하게 사용된다. 그 이상일 때는 운영체제 환경, JDK 종류/ | ||
+ | * [[java: | ||
===== Heap Dump on OutOfMemoryError ===== | ===== Heap Dump on OutOfMemoryError ===== | ||
줄 9: | 줄 35: | ||
</ | </ | ||
* '' | * '' | ||
+ | * '' | ||
===== jmap ===== | ===== jmap ===== | ||
줄 36: | 줄 63: | ||
===== jhat ===== | ===== jhat ===== | ||
* 힙 덤프를 분석한다. | * 힙 덤프를 분석한다. | ||
- | * '' | + | * '' |
* 힘 덤프 파일의 크기가 클 경우 OOM 에러가 발생할 수 있으므로 '' | * 힘 덤프 파일의 크기가 클 경우 OOM 에러가 발생할 수 있으므로 '' | ||
* 메모리를 너무 많이 먹어서 실제로 제대로 실행하기 힘듬. | * 메모리를 너무 많이 먹어서 실제로 제대로 실행하기 힘듬. | ||
줄 80: | 줄 107: | ||
| gcutil | GC 통계 데이터의 개요| | | gcutil | GC 통계 데이터의 개요| | ||
| printcompilation |HotSpot 컴파일 방법의 통계 데이터| | | printcompilation |HotSpot 컴파일 방법의 통계 데이터| | ||
+ | |||
+ | ===== SSH로 특정 서버의 GC 상태보기 ===== | ||
+ | 서버가 여러대일 경우 특정 서버에 자동 접속하여 해당 서버의 Tomcat 인스턴스를 찾아서 gcutil 실행 | ||
+ | <code sh> | ||
+ | ssh myhostname 'bash -s' <<' | ||
+ | jstat -gcutil `jps | grep Bootstrap | awk ' | ||
+ | ENDSSH | ||
+ | </ | ||
+ | |||
+ | ===== Code로 heap dump 뜨기 ===== | ||
+ | * [[https:// | ||
+ | <code java> | ||
+ | import javax.management.MBeanServer; | ||
+ | import java.lang.management.ManagementFactory; | ||
+ | |||
+ | import com.sun.management.HotSpotDiagnosticMXBean; | ||
+ | |||
+ | /** | ||
+ | * 현재 Java Application의 Heap Dump를 뜨는 함수 | ||
+ | * @see <a href=" | ||
+ | */ | ||
+ | public class HeapDumper { | ||
+ | // This is the name of the HotSpot Diagnostic MBean | ||
+ | private static final String HOTSPOT_BEAN_NAME = | ||
+ | " | ||
+ | // 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 | ||
+ | | ||
+ | */ | ||
+ | public static void dumpHeap(String fileName, boolean live) { | ||
+ | // initialize hotspot diagnostic MBean | ||
+ | initHotspotMBean(); | ||
+ | try { | ||
+ | hotspotMBean.dumpHeap(fileName, | ||
+ | } 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, | ||
+ | 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 = " | ||
+ | // by default dump only the live objects | ||
+ | boolean live = true; | ||
+ | // simple command line options | ||
+ | switch (args.length) { | ||
+ | case 2: | ||
+ | live = args[1].equals(" | ||
+ | case 1: | ||
+ | fileName = args[0]; | ||
+ | } | ||
+ | // dump the heap | ||
+ | dumpHeap(fileName, | ||
+ | } | ||
+ | } | ||
+ | </ | ||