modeler java堆空间,JVM|02内存模型
JVM內存模型
概述
Java內存模型(Java Memory Model ,JMM)就是一種符合內存模型規范的,屏蔽了各種硬件和操作系統的訪問差異的,保證了Java程序在各種平臺下對內存的訪問都能保證效果一致的機制及規范。
根據java虛擬機的規范,我們可以將JVM的內存分為五大塊
程序計數器
程序計數器是一個線程私有的,是一塊很小的區間,可以被理解為程序記錄行號器。
為什么說是線程私有的呢?
因為線程在多線程的情況下,需要進行來回的切換線程,所以就需要有一個程序計數器來記錄下當前線程跳轉之前執行到的地方的位置,所以這塊區域只能是線程私有的。
如果線程執行的是java方法,那么程序計數器記錄的將會是虛擬字節碼指令的地址;如果是native方法,計數器將會為null,此時的線程不需要他來記錄斷點的地方,會由底層匯編語言記錄;
程序計數器區是唯一的一個沒有OutOfMemoryError的區域。
虛擬機棧
虛擬機棧也是一個線程私有的,內部存放的是一個個的棧幀,棧幀存放的就是一個個的方法,內部所存儲的是方法的運行信息,包括局部變量表、操作數棧、動態連接、方法的返回地址信息。
棧的數據結構是先進后出,而我們平時說的棧其實是在指局部變量表,它的最小的局部變量表空間單位為Slot,虛擬機沒有指明Slot的大小,但在jvm中,long和double類型數據明確規定為64位,這兩個類型占2個Slot,其它基本類型固定占用1個Slot,而我們的方法內部的一些局部變量以及需要用到的全局變量都會放在方法的局部變量表中。
操作數棧是一塊用來進行對局部變量表中的變量進行操作的區域,也是先進后出;
譬如我們要對i進行i++,步驟如下:
方法先將i的放入局部變量表中,后將i的值壓入操作數棧中,后將1壓入操作數棧中,執行反編譯指令iadd,讓棧頂兩int型數值出棧并且相加,結果壓進操作數棧中,然后將操作數棧頂元素pop出放回局部變量表中的i對應的值。
方法返回地址:指向一條字節碼指令的地址
棧幀與局部變量表都是在編譯期間確定的內存空間,運行期間不會改變。
Java虛擬機棧可能出現兩種類型的異常:
線程請求的棧深度大于虛擬機允許的棧深度,將拋出StackOverflowError。
虛擬機棧空間可以動態擴展,當動態擴展是無法申請到足夠的空間時,拋出OutOfMemory異常。
本地方法棧
本地方法棧的調用與虛擬機棧十分相似,但是本地方法棧是在調用native方法才會使用的,底層調用的是系統的C或者C++的方法。
方法區
方法區是線程共享的,用于存儲已被虛擬機加載的類信息、常量、靜態變量,如static修飾的變量加載類的時候就被加載到方法區中。
方法區內部還有一塊運行常量池,用于存放編譯期間生成的各種字面量和符號引用。
堆
堆是一塊線程共享的,多線程的情況下需要線程同步機制,它的目的是存放對象實例。
jdk1.8的堆內存模型如下:
年輕代Young Generation:
絕大部分的新建的對象都放在Eden Memory,如果Eden Memory溢出了,則要進行GC回收
后將未被GC回收的對象放入移動到 From Survivor 或 To Survivor 中。
此時 Minor GC 也會檢查和移動 From Survivor 和 To Survivor中的對象,目的使 From Survivor,To Survivor其中一個置為空。在這個過程中會進行對象被移動次數的統計,設計一個移動次數的閾值
對于多次在survivor區中移動并且沒有被GC的超過閾值的對象,會被移動到老年代;
老年代 Old Generation
與 Young Generation相同,當 Old Generation區滿了之后將執行 GC 操作,該操作稱為:Major GC,耗用的時間也相對較長。
Young Generation和 Old Generation都可以主動觸發 stop-the-world 事件,掛起所有任務,執行 GC 操作。被掛起的任務只有在 GC 執行完畢后,才會恢復執行。
多數情況下, GC 性能調優(GC tuning)就是指降低 stop-the-world 時 GC 執行的時間。
圖中還有一塊區域沒有顯示出來,就是元數據空間,
Metaspace所占用的內存空間不是在虛擬機內部,而是在本地內存空間中,這也是與1.7的永久代最大的區別所在。而元數據空間就是上文說到的方法區存放的東西。
至于為什么還有這樣的區分:我的理解是方法區是jvm虛擬機規范的一種說法,具體的落地實踐在jdk1.7是通過在堆中定義一個永久代來實現,jdk1.8是通過在堆外定義的一個元數據空間來實現。
為什么jdk1.7的永久區要被廢除:
官網給出的解釋是:
This is part of the JRockit and Hotspot convergence effort. JRockit
customers do not need to configure the permanent generation (since JRockit
does not have a permanent generation) and are accustomed to not
configuring the permanent generation.
移除永久代是為融合HotSpot JVM與 JRockit VM而做出的努力,因為JRockit沒有永久代,
不需要配置永久代
現實使用中,由于永久代內存經常不夠用或發生內存泄露,爆出異常
java.lang.OutOfMemoryError: PermGen。
基于此,將永久區廢棄,而改用元空間,改為了使用本地內存空間。
JVM內存分析指令
通過jstat命令進行查看堆內存使用情況
jstat命令可以查看堆內存各部分的使用量,以及加載類的數量。命令的格式如下:
jstat [-命令選項] [端口號] [間隔時間/毫秒] [查詢次數]
常用的有三個命令選項
1. -class 查看類加載統計
[root@hadoop101 ~]# jps
3846 Bootstrap
6714 Jps
[root@hadoop101 ~]# jstat -class 3846
Loaded Bytes Unloaded Bytes Time
3612 7741.5 0 0.0 7.58
解釋:
Loaded:加載class的數量
Bytes:所占用空間大小
Unloaded:未加載數量
Bytes:未加載占用空間
Time:時間
2. -compiler 查看編譯統計
[root@hadoop101 ~]# jstat -compiler 3846
Compiled Failed Invalid Time FailedType FailedMethod
2174 0 0 6.38 0
解釋:
Compiled:編譯數量。
Failed:失敗數量
Invalid:不可用數量
Time:時間
FailedType:失敗類型
FailedMethod:失敗的方法
3. -gc 查看垃圾回收統計(十分常用)
[root@hadoop101 ~]# jstat -gc 3846
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1536.0 1536.0 0.0 32.6 12352.0 3144.9 30820.0 20681.0 25344.0 24556.2 2816.0 2588.3 15 0.417 1 0.075 0.493
# 間隔1秒 收集五次
[root@hadoop101 ~]# jstat -gc 3846 1000 5
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1536.0 1536.0 0.0 32.6 12352.0 3144.9 30820.0 20681.0 25344.0 24556.2 2816.0 2588.3 15 0.417 1 0.075 0.493
1536.0 1536.0 0.0 32.6 12352.0 3144.9 30820.0 20681.0 25344.0 24556.2 2816.0 2588.3 15 0.417 1 0.075 0.493
1536.0 1536.0 0.0 32.6 12352.0 3144.9 30820.0 20681.0 25344.0 24556.2 2816.0 2588.3 15 0.417 1 0.075 0.493
1536.0 1536.0 0.0 32.6 12352.0 3144.9 30820.0 20681.0 25344.0 24556.2 2816.0 2588.3 15 0.417 1 0.075 0.493
1536.0 1536.0 0.0 32.6 12352.0 3144.9 30820.0 20681.0 25344.0 24556.2 2816.0 2588.3 15 0.417 1 0.075 0.493
解釋:(你會發現總有一個survivor是空的,這也印證了我上面說到的年輕代的存儲方式)
S0C:第一個Survivor區的大小(KB)
S1C:第二個Survivor區的大小(KB)
S0U:第一個Survivor區的使用大小(KB)
S1U:第二個Survivor區的使用大小(KB)
EC:Eden區的大小(KB)
EU:Eden區的使用大小(KB)
OC:Old區大小(KB)
OU:Old使用大小(KB)
MC:方法區大小(KB)
MU:方法區使用大小(KB)
CCSC:壓縮類空間大小(KB)
CCSU:壓縮類空間使用大小(KB)
YGC:年輕代垃圾回收次數
YGCT:年輕代垃圾回收消耗時間
FGC:老年代垃圾回收次數
FGCT:老年代垃圾回收消耗時間
GCT:垃圾回收消耗總時間
通過jmap指令來分析內存溢出
前面通過jstat可以對jvm堆的內存進行統計分析,而jmap可以獲取到更加詳細的內容,
如:內存使用情況的匯總、對內存溢出的定位與分析。
查看內存使用情況
指令格式:jmap -heap 端口號
[root@hadoop101 ~]# jmap -heap 3846
Attaching to process ID 3846, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.111-b14
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration: # 堆內存的配置信息
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 482344960 (460.0MB)
NewSize = 10485760 (10.0MB)
MaxNewSize = 160759808 (153.3125MB)
OldSize = 20971520 (20.0MB)
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 = 14221312 (13.5625MB)
used = 4445184 (4.2392578125MB)
free = 9776128 (9.3232421875MB)
31.257200460829495% used
Eden Space: # Eden 使用情況
capacity = 12648448 (12.0625MB)
used = 4411808 (4.207427978515625MB)
free = 8236640 (7.855072021484375MB)
34.880231946243526% used
From Space: # From Surivior 使用情況
capacity = 1572864 (1.5MB)
used = 33376 (0.031829833984375MB)
free = 1539488 (1.468170166015625MB)
2.1219889322916665% used
To Space: # To Survivor 使用情況
capacity = 1572864 (1.5MB)
used = 0 (0.0MB)
free = 1572864 (1.5MB)
0.0% used
tenured generation: # 老年代
capacity = 31559680 (30.09765625MB)
used = 21177312 (20.196258544921875MB)
free = 10382368 (9.901397705078125MB)
67.10242942894224% used
13885 interned Strings occupying 1883624 bytes.
查看內存中對象數量及大小
查看所有對象,包括活躍以及非活躍的
jmap ‐histo 端口號 | more
查看活躍對象
jmap ‐histo:live 端口號 | more
[root@hadoop101 ~]# jmap -histo:live 3846 | more
num #instances #bytes class name
----------------------------------------------
1: 36197 6581296 [C
2: 3052 1689256 [I
3: 985 1004736 [B
4: 34556 829344 java.lang.String
5: 15257 488224 java.util.HashMap$Node
6: 4042 466008 java.lang.Class
7: 4453 391864 java.lang.reflect.Method
8: 4214 265160 [Ljava.lang.Object;
9: 6799 217568 java.util.concurrent.ConcurrentHashMap$Node
10: 977 175600 [Ljava.util.HashMap$Node;
11: 89 104880 [Ljava.util.concurrent.ConcurrentHashMap$Node;
12: 5975 95600 java.lang.Object
13: 1177 84016 [Ljava.lang.String;
14: 1615 77520 java.util.HashMap
15: 2602 54072 [Ljava.lang.Class;
16: 89 49424 [Ljava.util.WeakHashMap$Entry;
17: 608 48640 java.lang.reflect.Constructor
18: 1430 45760 java.util.Hashtable$Entry
19: 1096 43840 java.lang.ref.SoftReference
20: 1047 41880 java.util.LinkedHashMap$Entry
21: 1027 41080 java.util.TreeMap$Entry
22: 837 40176 org.apache.tomcat.util.modeler.AttributeInfo
23: 9 37008 [Ljava.nio.ByteBuffer;
24: 52 35264 [S
25: 125 34416 [[C
26: 974 31168 java.lang.ref.WeakReference
27: 1180 28320 java.util.ArrayList
解釋:
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=目標文件全路徑 端口號
[root@hadoop101 ~]# jmap -dump:format=b,file=dump.dat 3846
Dumping heap to /root/dump.dat ...
Heap dump file created
[root@hadoop101 ~]# ll
total 37788
-rw-------. 1 root root 5418 Apr 6 2017 anaconda-ks.cfg
-rw-------. 1 root root 29300407 Aug 14 14:16 dump.dat
drwxr-xr-x. 2 root root 6 Aug 14 08:54 jvm
-rw-r--r--. 1 root root 571 Aug 14 10:32 JvmTest.class
-rw-r--r--. 1 root root 250 Aug 14 08:56 JvmTest.java
-rw-r--r--. 1 root root 9366128 Apr 4 2017 node-v6.10.2-linux-x64.tar.xz
-rw-------. 1 root root 5098 Apr 6 2017 original-ks.cfg
[root@hadoop101 ~]#
通過jhat對dump文件進行分析
我們將jvm的內存dump到文件中,這個文件是一個二進制的文件,不方便查看,這時我們可以借助于jhat工具進行查看。
語法: jhat ‐port 瀏覽器訪問端口號 文件
[root@hadoop101 ~]# jhat -port 8081 dump.dat
Reading from dump.dat...
Dump file created Wed Aug 14 14:16:57 UTC 2019
Snapshot read, resolving...
Resolving 271656 objects...
Chasing references, expect 54 dots......................................................
Eliminating duplicate references......................................................
Snapshot resolved.
Started HTTP server on port 8081
Server is ready.
我們可以通過服務器ip:8081查看
在最后還有一個OQL的查詢功能,語法類似SQL,可以快速查詢到想要看的數據
總結
以上是生活随笔為你收集整理的modeler java堆空间,JVM|02内存模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab ceil,matla
- 下一篇: php语言 电商网站,电商网站如何做多语