JAVA 어플리케이션을 구동할때 메모리 사용량은 중요하다 static 메모리를 필요 이상으로 많이 사용하거나 힙메모리의 사용량이 이상하게 점점증가해서 메모리 초과가 발생하는 등 메모리 사용량의 이상 동작이 느껴질때는 메모리 덤프를 떠서 직접 확인해보는게 가장 좋다.
물론 더 유용한 도구들도 많겠지만 java-jdk가 깔려있다면 누구나 설치되어있는 가장 기본적인 툴을 사용 할 줄 알아야 추후 어떤 환경에서도 덤프 기능을 원활히 사용 할 수 있을것 같아 jps, jmap, jhat을 사용하려 한다.
1. jps 명령어
유닉스의 명령어중 'ps'는 현재 실행되고 있는 프로세스들을 표시하는 명령어인데
'jps'명령어는 현재 실행되고있는 JVM 프로세스를 표시해준다.
kys@DESKTOP-7JHK5HR ~ jps
4176 Bootstrap
6081 Jps
5208 MonitoringServer
4543 SocketServer
참고. jps -v 옵션을 사용하면 구동시 입력했던 JVM 파라미터도 함께 보여준다.
2. jmap 명령어
jmap명령어는 jvm의 맵을 보여주는 기능을 제공하는 기본 분석 도구이다.
따라서 자바 힙 메모리의 정보를 얻거나 메모리 dump를 떠서 분석을 할 수 있다.
kys@DESKTOP-7JHK5HR ~ jmap -heap 4543
Attaching to process ID 4543, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.312-b07
using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 697892864 (665.5625MB)
MaxNewSize = 697892864 (665.5625MB)
OldSize = 375848960 (358.4375MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.tools.jmap.JMap.runTool(JMap.java:201)
at sun.tools.jmap.JMap.main(JMap.java:130)
Caused by: java.lang.RuntimeException: unknown CollectedHeap type : class sun.jvm.hotspot.gc_interface.CollectedHeap
at sun.jvm.hotspot.tools.HeapSummary.run(HeapSummary.java:144)
at sun.jvm.hotspot.tools.Tool.startInternal(Tool.java:260)
at sun.jvm.hotspot.tools.Tool.start(Tool.java:223)
at sun.jvm.hotspot.tools.Tool.execute(Tool.java:118)
at sun.jvm.hotspot.tools.HeapSummary.main(HeapSummary.java:49)
... 6 more
잘 나가다가 위와 같은 오류가 발생했다.
oracle jdk같은 경우 문제가 발생 하지 않지만 openjdk같은 경우 위와 같은 문제가 발생한다고 한다.
따라서 해결하려면 debug기능을 포함한 jdk패키지를 받으면 된다.
openjdk-8 버전을 사용중이라서 해당 JVM에 맞는 debug패키지를 설치해준다.
kys@DESKTOP-7JHK5HR ~ sudo apt list | grep openjdk-8
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
openjdk-8-dbg/focal-updates,focal-security 8u312-b07-0ubuntu1~20.04 amd64
openjdk-8-demo/focal-updates,focal-security 8u312-b07-0ubuntu1~20.04 amd64
openjdk-8-doc/focal-updates,focal-security 8u312-b07-0ubuntu1~20.04 all
openjdk-8-jdk-headless/focal-updates,focal-security,now 8u312-b07-0ubuntu1~20.04 amd64 [installed,automatic]
openjdk-8-jdk/focal-updates,focal-security,now 8u312-b07-0ubuntu1~20.04 amd64 [installed]
openjdk-8-jre-headless/focal-updates,focal-security,now 8u312-b07-0ubuntu1~20.04 amd64 [installed,automatic]
openjdk-8-jre-zero/focal-updates,focal-security 8u312-b07-0ubuntu1~20.04 amd64
openjdk-8-jre/focal-updates,focal-security,now 8u312-b07-0ubuntu1~20.04 amd64 [installed,automatic]
openjdk-8-source/focal-updates,focal-security 8u312-b07-0ubuntu1~20.04 all
kys@DESKTOP-7JHK5HR ~ sudo apt install openjdk-8-dbg
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
openjdk-8-dbg
0 upgraded, 1 newly installed, 0 to remove and 163 not upgraded.
Need to get 2050 kB of archives.
After this operation, 6538 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu focal-updates/universe amd64 openjdk-8-dbg amd64 8u312-b07-0ubuntu1~20.04 [2050 kB]
Fetched 2050 kB in 4s (536 kB/s)
Selecting previously unselected package openjdk-8-dbg:amd64.
(Reading database ... 49108 files and directories currently installed.)
Preparing to unpack .../openjdk-8-dbg_8u312-b07-0ubuntu1~20.04_amd64.deb ...
Unpacking openjdk-8-dbg:amd64 (8u312-b07-0ubuntu1~20.04) ...
Setting up openjdk-8-dbg:amd64 (8u312-b07-0ubuntu1~20.04) ...
kys@DESKTOP-7JHK5HR ~ jmap -heap 4543
Attaching to process ID 4543, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.312-b07
using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 697892864 (665.5625MB)
MaxNewSize = 697892864 (665.5625MB)
OldSize = 375848960 (358.4375MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 628162560 (599.0625MB)
used = 545135192 (519.8814315795898MB)
free = 83027368 (79.18106842041016MB)
86.78250292408386% used
Eden Space:
capacity = 558432256 (532.5625MB)
used = 529401240 (504.8763656616211MB)
free = 29031016 (27.686134338378906MB)
94.8013361176615% used
From Space:
capacity = 69730304 (66.5MB)
used = 15733952 (15.00506591796875MB)
free = 53996352 (51.49493408203125MB)
22.564008899201127% used
To Space:
capacity = 69730304 (66.5MB)
used = 0 (0.0MB)
free = 69730304 (66.5MB)
0.0% used
concurrent mark-sweep generation:
capacity = 375848960 (358.4375MB)
used = 0 (0.0MB)
free = 375848960 (358.4375MB)
0.0% used
위와같이 정상적으로 해당 java process에 대한 heap메모리 사용현황 요약정보를 얻을 수 있다.
두번째.
-histo옵션을 이용하여 JVM 프로세스의 메모리 통계[histogram]를 알아 볼 수 있다.
kys@DESKTOP-7JHK5HR ~ jmap -histo 4543
num #instances #bytes class name
----------------------------------------------
1: 192270 326561288 [B
2: 507238 77324520 [C
3: 164075 68671040 [I
4: 578939 18526048 java.lang.StackTraceElement
5: 249436 9977440 java.util.TreeMap$Entry
6: 131881 9069976 [Ljava.lang.Object;
7: 291253 6990072 java.lang.String
8: 78736 6215256 [S
9: 46477 5986992 [Ljava.lang.StackTraceElement;
10: 55433 2732384 [Ljava.lang.String;
11: 141343 2261488 java.lang.Integer
12: 29570 1892480 java.nio.DirectByteBuffer
13: 71938 1726512 java.lang.StringBuilder
14: 41156 1646240 java.util.PriorityQueue$Itr
15: 31379 1506192 java.util.HashMap
16: 15490 1115280 ch.qos.logback.classic.spi.LoggingEvent
.
.
.
.
.
.
Total 3362721 574166208
위와같이 히스토그램을 보고 특정 클래스가 유별나게 많이 할당되어있다면 해당 소스를 확인 해 볼 수 있다.
마지막.
메모리덤프 파일을 생성하여 다른 분석 도구를 이용하여 확인 하는 방식이다.
## 명령어
$) jmap -dump:file={dump file 이름} PID
보통 덤프파일은 .hprof 확장자를 사용한다.
test.hprof를 생성해보자
kys@DESKTOP-7JHK5HR ~ jmap -dump:file=test.hprof 4543
Dumping heap to /home/kys/test.hprof ...
Heap dump file created
3. jhat (Java Heap Anlyzer Tool)
jmap으로 만들어놓은 .hprof 힙 메모리 덤프파일을 분석하는 가장 기본적인 분석 도구로서
jdk에 내장되어있다.
## 명령어
jhat {dump file}
위의 명령어를 사용하면 7000번 포트를 사용하는 웹서버로 배포가 진행된다.
contextPath = / (루트) 이며 사용자가 7000번을 사용하고있다면 -port 옵션으로 포트를 변경하여 배포 할 수 있다.
kys@DESKTOP-7JHK5HR ~ jhat test.hprof
Reading from test.hprof...
Dump file created Mon May 16 11:55:14 KST 2022
Snapshot read, resolving...
Resolving 488975 objects...
Chasing references, expect 97 dots.................................................................................................
Eliminating duplicate references.................................................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
해당 화면이 뜨면서 커맨드를 더이상 입력 할 수 없는 상태로 되며 배포가 진행되었음을 확인 할 수있다.
(만약 커맨드를 계속 치고싶다면 nohup 명령어를 이용해서 실행하면 되겠죠?)
4. 기타 분석 도구들
jmap으로 hprof파일을 생성한뒤 다른 분석도구를 이용하여 해당 덤프내용을 분석 할 수도 있다.
Eclipse Memory Analyzer 라는 분석도구를 많이 사용 하는것 같다.
내가 사용하고 있는 IntelliJ 에서도 파일을 열어보니 제대로 작동하는것 같다.
나중에 써보고 어떤게 좋은지 알아보면 될것같다.
'JAVA' 카테고리의 다른 글
Scanner 클래스 사용법 (0) | 2021.09.14 |
---|