jinfo使用
可以查看java的系統參數
可以查看某個JVM的參數
可以調整某個JVM的參數
查看jvm的參數
λ jps
9920 jar
3524
1512 Launcher
10028 Jps
λ jinfo -flags 9920
Attaching to process ID 9920, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.171-b11
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=132120576 -XX:MaxHeapSize=2105540608 -XX:MaxNewSize=701497344 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44040192 -XX:OldSize=88080384 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:
查看java系統參數
λ jinfo -sysprops 9920
Attaching to process ID 9920, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.171-b11
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.171-b11
sun.boot.library.path = C:\Program Files\Java\jre1.8.0_171\bin
java.protocol.handler.pkgs = org.springframework.boot.loader
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = ;
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level = Service Pack 1
sun.java.launcher = SUN_STANDARD
user.script =
user.country = CN
。。。。
Jstat
jstat命令可以查看堆內存各部分的使用量,以及加載類的數量。命令的格式如下:
jstat [-命令選項] [vmid] [間隔時間/毫秒] [查詢次數]
類加載統計:
λ jstat.exe -class 9920
Loaded Bytes Unloaded Bytes Time
10016 17802.1 0 0.0 16.63
垃圾回收統計
λ jstat.exe -gc 9920
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
11776.0 10752.0 0.0 8965.3 656384.0 162951.3 91136.0 31814.1 48896.0 47920.8 6400.0 6203.8 15 0.305 2 0.165 0.470
λ jjstat.exe -gc 9920 1000 5
#也可以指定打印的間隔和次數,每1秒中打印一次,共打印5次
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
512.0 512.0 128.0 0.0 30208.0 23473.1 91136.0 37991.3 51072.0 50049.2 6784.0 6504.7 262 1.565 2 0.165 1.730
512.0 512.0 0.0 128.0 30208.0 4820.6 91136.0 37991.3 51072.0 50049.2 6784.0 6504.7 263 1.567 2 0.165 1.732
512.0 512.0 0.0 128.0 30208.0 15649.0 91136.0 37991.3 51072.0 50049.2 6784.0 6504.7 263 1.567 2 0.165 1.732
512.0 512.0 0.0 128.0 30208.0 27050.5 91136.0 37991.3 51072.0 50049.2 6784.0 6504.7 263 1.567 2 0.165 1.732
512.0 512.0 128.0 0.0 30208.0 7565.2 91136.0 37991.3 51072.0 50049.2 6784.0 6504.7 264 1.569 2 0.165 1.734
- S0C:第一個倖存區的大小 (Kb)
- S1C:第二個倖存區的大小 (Kb)
- S0U:第一個倖存區的使用大小 (Kb)
- S1U:第二個倖存區的使用大小 (Kb)
- EC:伊甸園區的大小 (Kb)
- EU:伊甸園區的使用大小 (Kb)
- OC:老年代大小 (Kb)
- OU:老年代使用大小 (Kb)
- MC:方法區大小(元空間) (Kb)
- MU:方法區使用大小 (Kb)
- CCSC:壓縮類空間大小 (Kb)
- CCSU:壓縮類空間使用大小
- YGC:年輕代垃圾回收次數
- YGCT:年輕代垃圾回收消耗時間
- FGC:老年代垃圾回收次數
- FGCT:老年代垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
堆內存統計:
λ jstat.exe -gccapacity 9920
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
43008.0 685056.0 685056.0 11776.0 10752.0 656384.0 86016.0 1371136.0 91136.0 91136.0 0.0 1091584.0 48896.0 0.0 1048576.0 6400.0 15 2
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:當前新生代容量
- S0C:第一個倖存區大小
- S1C:第二個倖存區的大小
- EC:伊甸園區的大小
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:當前老年代大小
- OC:當前老年代大小
- MCMN:最小元數據容量
- MCMX:最大元數據容量
- MC:當前元數據空間大小
- CCSMN:最小壓縮類空間大小
- CCSMX:最大壓縮類空間大小
- CCSC:當前壓縮類空間大小
- YGC:年輕代gc次數
- FGC:老年代GC次數
新生代內存統計
λ jstat.exe -gcnew 9920
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
11776.0 10752.0 0.0 8965.3 2 15 11776.0 656384.0 169515.4 15 0.305
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:當前新生代容量
- S0CMX:最大幸存1區大小
- S0C:當前倖存1區大小
- S1CMX:最大幸存2區大小
- S1C:當前倖存2區大小
- ECMX:最大伊甸園區大小
- EC:當前伊甸園區大小
- YGC:年輕代垃圾回收次數
- FGC:老年代回收次數
老年代垃圾回收統計
λ jstat.exe -gcold 9920
MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
48896.0 47920.8 6400.0 6203.8 91136.0 31814.1 15 2 0.165 0.470
- MC:方法區大小
- MU:方法區使用大小
- CCSC:壓縮類空間大小
- CCSU:壓縮類空間使用大小
- OC:老年代大小
- OU:老年代使用大小
- YGC:年輕代垃圾回收次數
- FGC:老年代垃圾回收次數
- FGCT:老年代垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
老年代內存統計
λ jstat.exe -gcoldcapacity 9920
OGCMN OGCMX OGC OC YGC FGC FGCT GCT
86016.0 1371136.0 91136.0 91136.0 15 2 0.165 0.470
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:當前老年代大小
- OC:老年代大小
- YGC:年輕代垃圾回收次數
- FGC:老年代垃圾回收次數
- FGCT:老年代垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
元數據空間統計
λ jstat.exe -gcmetacapacity 9920
MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT
0.0 1091584.0 48896.0 0.0 1048576.0 6400.0 15 2 0.165 0.470
- MCMN:最小元數據容量
- MCMX:最大元數據容量
- MC:當前元數據空間大小
- CCSMN:最小壓縮類空間大小
- CCSMX:最大壓縮類空間大小
- CCSC:當前壓縮類空間大小
- YGC:年輕代垃圾回收次數
- FGC:老年代垃圾回收次數
- FGCT:老年代垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
gc工具gcutil參數
λ jstat.exe -gcutil 9920
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 83.38 26.33 34.91 98.01 96.93 15 0.305 2 0.165 0.470
- S0:倖存1區當前使用比例
- S1:倖存2區當前使用比例
- E:伊甸園區使用比例
- O:老年代使用比例
- M:元數據區使用比例
- CCS:壓縮使用比例
- YGC:年輕代垃圾回收次數
- FGC:老年代垃圾回收次數
- FGCT:老年代垃圾回收消耗時間
- GCT:垃圾回收消耗總時間
jmap
前面通過jstat可以對jvm堆的內存進行統計分析,而jmap可以獲取到更加詳細的內容,
如:內存使用情況的彙總、對內存溢出的定位與分析
堆信息:
λ jmap.exe -heap 9920
Attaching to process ID 9920, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.171-b11
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 2105540608 (2008.0MB)
NewSize = 44040192 (42.0MB)
MaxNewSize = 701497344 (669.0MB)
OldSize = 88080384 (84.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 672137216 (641.0MB)
used = 176945008 (168.74790954589844MB)
free = 495192208 (472.25209045410156MB)
26.325726918236885% used
From Space:
capacity = 11010048 (10.5MB)
used = 9180504 (8.755210876464844MB)
free = 1829544 (1.7447891235351562MB)
83.38296072823661% used
To Space:
capacity = 12058624 (11.5MB)
used = 0 (0.0MB)
free = 12058624 (11.5MB)
0.0% used
PS Old Generation
capacity = 93323264 (89.0MB)
used = 32577656 (31.06847381591797MB)
free = 60745608 (57.93152618408203MB)
34.90839754597525% used
25513 interned Strings occupying 3131664 bytes.
查看內存中對象數量及大小
#查看所有對象,包括活躍以及非活躍的
jmap ‐histo <pid> | more
#查看活躍對象
jmap ‐histo:live <pid> | more'
λ jmap.exe -histo:live 9920 | more
num #instances #bytes class name
----------------------------------------------
1: 66633 8976600 [C
2: 64870 1556880 java.lang.String
3: 40185 1285920 java.util.concurrent.ConcurrentHashMap$Node
4: 10604 1178176 java.lang.Class
5: 8574 754512 java.lang.reflect.Method
6: 3987 734032 [B
7: 17124 684960 java.util.LinkedHashMap$Entry
8: 5074 684432 [I
9: 7759 550680 [Ljava.util.HashMap$Node;
10: 9423 527688 java.util.LinkedHashMap
11: 9325 518128 [Ljava.lang.Object;
12: 260 502688 [Ljava.util.concurrent.ConcurrentHashMap$Node;
13: 25660 410560 java.lang.Object
14: 12815 410080 java.util.HashMap$Node
15: 3754 150160 java.lang.ref.SoftReference
16: 1555 149280 org.springframework.beans.GenericTypeAwarePropertyDescriptor
17: 4567 146144 java.lang.ref.WeakReference
某測試環境發現部署的java進程(pid=1)經常full GC,長期內存佔用很高,疑似內存泄漏,現在想要確定是哪些類的實例佔用內存較多,那麼應該用下列選項中的那個命令:
./jdk1.8.0_151/bin/jmap -histo 1
[service@usg-smn-191130100-8546f8ccd9-kfh6w usg]$ ./jdk1.8.0_151/bin/jmap -histo 1
Picked up JAVA_TOOL_OPTIONS: -javaagent:/paas-apm/collectors/pinpoint/pinpoint-bootstrap.jar -Dpinpoint.config=/paas-apm/collectors/pinpoint/pinpoint.config -Duser.stemming.config=/paas-apm/collectors/pinpoint/userStemming.config
num #instances #bytes class name
----------------------------------------------
1: 2296244 231628904 [C
2: 416554 53976048 [B
3: 6283 37337624 [J
4: 1360072 32641728 java.lang.String
5: 96883 18168224 [I
6: 253392 16217088 java.net.URL
7: 332371 15953808 java.util.HashMap
8: 260721 13617384 [Ljava.util.HashMap$Node;
9: 218684 12189896 [Ljava.lang.Object;
10: 257915 8253280 java.util.concurrent.locks.AbstractQueuedSynchronizer$Node
11: 244856 7835392 org.springframework.boot.loader.jar.StringSequence
12: 168575 6743000 java.util.LinkedHashMap$Entry
13: 244856 5876544
#對象說明
B byte
C char
D double
F float
I int
J long
Z boolean
[ 數組,如[I表示int[]
[L+類名 其他對象
堆內存dump
有些時候我們需要將jvm當前內存中的情況dump到文件中,然後對它進行分析,jmap也
是支持dump到文件中的
#用法:
jmap ‐dump:format=b,file=dumpFileName <pid>
#示例
jmap ‐dump:format=b,file=/tmp/dump.dat 6219
D:\
λ jmap.exe -dump:format=b,file=eureka.hprof 9920
Dumping heap to D:\eureka.hprof ...
Heap dump file created
也可以設置內存溢出自動導出dump文件(內存很大的時候,可能會導不出來)
jstack的使用:
有些時候我們需要查看下jvm中的線程執行情況,比如,發現服務器的CPU的負載突然增
高了、出現了死鎖、死循環等,我們該如何分析呢?
由於程序是正常運行的,沒有任何的輸出,從日誌方面也看不出什麼問題,所以就需要
看下jvm的內部線程的執行情況,然後再進行分析查找出原因。
這個時候,就需要藉助於jstack命令了,jstack的作用是將正在運行的jvm的線程情況進
行快照,並且打印出來
#用法:jstack <pid>
D:\IntelIJWorkSpace\jvm>jps
1264 Jps
3524
1512 Launcher
3516 DeadLockTest
D:\IntelIJWorkSpace\jvm>jstack 3516
2020-06-27 16:10:02
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode):
"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x00000000020e9000 nid=0x17ec waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #12 prio=5 os_prio=0 tid=0x00000000594c7800 nid=0xa54 waiting for monitor entry [0x000000005941f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at DeadLockTest.lambda$main$1(DeadLockTest.java:32)
- waiting to lock <0x00000000d648e630> (a java.lang.Object)
- locked <0x00000000d648e640> (a java.lang.Object)
at DeadLockTest$$Lambda$2/1831932724.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0" #11 prio=5 os_prio=0 tid=0x00000000594c2000 nid=0x1864 waiting for monitor entry [0x0000000059dbf000]
java.lang.Thread.State: BLOCKED (on object monitor)
at DeadLockTest.lambda$main$0(DeadLockTest.java:19)
- waiting to lock <0x00000000d648e640> (a java.lang.Object)
- locked <0x00000000d648e630> (a java.lang.Object)
at DeadLockTest$$Lambda$1/990368553.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x0000000058559800 nid=0x668 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x000000005854e800 nid=0x18bc waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x000000005853d000 nid=0x1c0c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x000000005853c800 nid=0xf90 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x0000000058539800 nid=0x1860 runnable [0x00000000589fe000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x00000000d652cb40> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x00000000d652cb40> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000584e8800 nid=0x188c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000572c0000 nid=0x1d10 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x00000000572a5800 nid=0x19c0 in Object.wait() [0x00000000584df000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d6308ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x00000000d6308ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:212)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000057264000 nid=0x19bc in Object.wait() [0x000000005819f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d6306bf8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000d6306bf8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=2 tid=0x000000005725c800 nid=0x1a50 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000020fe000 nid=0x19cc runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000020ff800 nid=0x1b34 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002101000 nid=0x1a4c runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000002102800 nid=0x12e0 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x0000000058624000 nid=0xd58 waiting on condition
JNI global references: 317
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00000000572b1148 (object 0x00000000d648e630, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x00000000572ae758 (object 0x00000000d648e640, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at DeadLockTest.lambda$main$1(DeadLockTest.java:32)
- waiting to lock <0x00000000d648e630> (a java.lang.Object)
- locked <0x00000000d648e640> (a java.lang.Object)
at DeadLockTest$$Lambda$2/1831932724.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at DeadLockTest.lambda$main$0(DeadLockTest.java:19)
- waiting to lock <0x00000000d648e640> (a java.lang.Object)
- locked <0x00000000d648e630> (a java.lang.Object)
at DeadLockTest$$Lambda$1/990368553.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
jstack找出佔用cpu最高的堆棧信息
1,使用命令top -p <pid> ,顯示你的java進程的內存情況,pid是你的java進程號,比如4977
4,轉爲十六進制得到 0x1371 ,此爲線程id的十六進制表示
5,執行 jstack 4977|grep -A 10 1371,得到線程堆棧信息中1371這個線程所在行的後面10行
用jstack查找死鎖,見如下示例,也可以用jvisualvm查看死鎖
JVisualVM使用
VisualVM,能夠監控線程,內存情況,查看方法的CPU時間和內存中的對 象,已被GC的
對象,反向查看分配的堆棧(如100個String對象分別由哪幾個對象分配出來的)。
VisualVM使用簡單,幾乎0配置,功能還是比較豐富的,幾乎囊括了其它JDK自帶命令的
所有功能。
- 內存信息
- 線程信息
- Dump堆(本地進程)
- Dump線程(本地進程)
- 打開堆Dump。堆Dump可以用jmap來生成。
- 打開線程Dump
- 生成應用快照(包含內存信息、線程信息等等)
- 性能分析。CPU分析(各個方法調用時間,檢查哪些方法耗時多),內存分析(各類
- 對象佔用的內存,檢查哪些類佔用內存多)
遠程連接jvisualvm
JMX(Java Management Extensions,即Java管理擴展)是一個爲應用程序、設備、系統等植入管理功能的框架。JMX可以跨越一系列異構操作系統平臺、系統體系結構和網絡傳輸協議,靈活的開發無縫集成的系統、網絡和服務管理應用
java -Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -jar foo.jar
java -Xms2048m -Xmx2048m -Xss256k -XX:MaxDirectMemorySize=256m -XX:+UseParallelOldGC -XX:+HeapDumpOnOutOfMemoryError -Djava.rmi.service.hostname=10.96.61.144 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dname=SmnService -cp ./ org.springframework.boot.loader.WarLauncher
啓動tomcat方式連接:
想要監控遠程的tomcat,就需要在遠程的tomcat進行對JMX配置,方法如下:
#在tomcat的bin目錄下,修改catalina.sh,添加如下的參數
JAVA_OPTS="‐Dcom.sun.management.jmxremote ‐
Dcom.sun.management.jmxremote.port=9999 ‐
Dcom.sun.management.jmxremote.authenticate=false ‐
Dcom.sun.management.jmxremote.ssl=false"
#這幾個參數的意思是:
#‐Dcom.sun.management.jmxremote :允許使用JMX遠程管理
#‐Dcom.sun.management.jmxremote.port=9999 :JMX遠程連接端口
#‐Dcom.sun.management.jmxremote.authenticate=false :不進行身份認證,任何用
戶都可以連接
#‐Dcom.sun.management.jmxremote.ssl=false :不使用ssl
保存退出,重啓tomcat。
jhat使用
使用MAT對dump文件分析
這裏講一下需要在官網上下載內存分析工具
內存溢出實戰
內存溢出在實際的生產環境中經常會遇到,比如,不斷的將數據寫入到一個集合中,出現了死循環,讀取超大的文件等等,都可能會造成內存溢出。如果出現了內存溢出,首先我們需要定位到發生內存溢出的環節,並且進行分析,是正
常還是非正常情況,如果是正常的需求,就應該考慮加大內存的設置,如果是非正常需求,那麼就要對代碼進行修改,修復這個bug。首先,我們得先學會如何定位問題,然後再進行分析。如何定位問題呢,我們需要藉助於jmap與MAT工具進行定位分析。
接下來,我們模擬內存溢出的場景。
編寫代碼,向List集合中添加100萬個字符串,每個字符串由1000個UUID組成。如果程
序能夠正常執行,最後打印ok。
package cn.itcast.jvm;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class TestJvmOutOfMemory {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < 10000000; i++) {
String str = "";
for (int j = 0; j < 1000; j++) {
str += UUID.randomUUID().toString();
}
list.add(str);
}
System.out.println("ok");
}
}
爲了演示效果,我們將設置執行的參數,這裏使用的是Idea編輯器。
#參數如下:
‐Xms8m ‐Xmx8m ‐XX:+HeapDumpOnOutOfMemoryError
"C:\Program Files\Java\jdk1.8.0_45\bin\java.exe" -Xms8m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError "-javaagent:D:\software_install\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=65345:D:\software_install\IntelliJ IDEA 2018.2.4\bin" -3.10.5.Final.jar" com.itcast.memory.JVMOutOfMemory
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid41500.hprof ...
Heap dump file created [9292666 bytes in 0.024 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:421)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at java.util.UUID.toString(UUID.java:378)
at com.itcast.memory.JVMOutOfMemory.main(JVMOutOfMemory.java:28)
Process finished with exit code 1