日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

modeler java堆空间,JVM|02内存模型

發(fā)布時間:2025/1/21 93 豆豆
生活随笔 收集整理的這篇文章主要介紹了 modeler java堆空间,JVM|02内存模型 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

JVM內存模型

概述

Java內存模型(Java Memory Model ,JMM)就是一種符合內存模型規(guī)范的,屏蔽了各種硬件和操作系統(tǒng)的訪問差異的,保證了Java程序在各種平臺下對內存的訪問都能保證效果一致的機制及規(guī)范。

根據(jù)java虛擬機的規(guī)范,我們可以將JVM的內存分為五大塊

程序計數(shù)器

程序計數(shù)器是一個線程私有的,是一塊很小的區(qū)間,可以被理解為程序記錄行號器。

為什么說是線程私有的呢?

因為線程在多線程的情況下,需要進行來回的切換線程,所以就需要有一個程序計數(shù)器來記錄下當前線程跳轉之前執(zhí)行到的地方的位置,所以這塊區(qū)域只能是線程私有的。

如果線程執(zhí)行的是java方法,那么程序計數(shù)器記錄的將會是虛擬字節(jié)碼指令的地址;如果是native方法,計數(shù)器將會為null,此時的線程不需要他來記錄斷點的地方,會由底層匯編語言記錄;

程序計數(shù)器區(qū)是唯一的一個沒有OutOfMemoryError的區(qū)域。

虛擬機棧

虛擬機棧也是一個線程私有的,內部存放的是一個個的棧幀,棧幀存放的就是一個個的方法,內部所存儲的是方法的運行信息,包括局部變量表、操作數(shù)棧、動態(tài)連接、方法的返回地址信息。

棧的數(shù)據(jù)結構是先進后出,而我們平時說的棧其實是在指局部變量表,它的最小的局部變量表空間單位為Slot,虛擬機沒有指明Slot的大小,但在jvm中,long和double類型數(shù)據(jù)明確規(guī)定為64位,這兩個類型占2個Slot,其它基本類型固定占用1個Slot,而我們的方法內部的一些局部變量以及需要用到的全局變量都會放在方法的局部變量表中。

操作數(shù)棧是一塊用來進行對局部變量表中的變量進行操作的區(qū)域,也是先進后出;

譬如我們要對i進行i++,步驟如下:

方法先將i的放入局部變量表中,后將i的值壓入操作數(shù)棧中,后將1壓入操作數(shù)棧中,執(zhí)行反編譯指令iadd,讓棧頂兩int型數(shù)值出棧并且相加,結果壓進操作數(shù)棧中,然后將操作數(shù)棧頂元素pop出放回局部變量表中的i對應的值。

方法返回地址:指向一條字節(jié)碼指令的地址

棧幀與局部變量表都是在編譯期間確定的內存空間,運行期間不會改變。

Java虛擬機棧可能出現(xiàn)兩種類型的異常:

線程請求的棧深度大于虛擬機允許的棧深度,將拋出StackOverflowError。

虛擬機棧空間可以動態(tài)擴展,當動態(tài)擴展是無法申請到足夠的空間時,拋出OutOfMemory異常。

本地方法棧

本地方法棧的調用與虛擬機棧十分相似,但是本地方法棧是在調用native方法才會使用的,底層調用的是系統(tǒng)的C或者C++的方法。

方法區(qū)

方法區(qū)是線程共享的,用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量,如static修飾的變量加載類的時候就被加載到方法區(qū)中。

方法區(qū)內部還有一塊運行常量池,用于存放編譯期間生成的各種字面量和符號引用。

堆是一塊線程共享的,多線程的情況下需要線程同步機制,它的目的是存放對象實例。

jdk1.8的堆內存模型如下:

年輕代Young Generation:

絕大部分的新建的對象都放在Eden Memory,如果Eden Memory溢出了,則要進行GC回收

后將未被GC回收的對象放入移動到 From Survivor 或 To Survivor 中。

此時 Minor GC 也會檢查和移動 From Survivor 和 To Survivor中的對象,目的使 From Survivor,To Survivor其中一個置為空。在這個過程中會進行對象被移動次數(shù)的統(tǒng)計,設計一個移動次數(shù)的閾值

對于多次在survivor區(qū)中移動并且沒有被GC的超過閾值的對象,會被移動到老年代;

老年代 Old Generation

與 Young Generation相同,當 Old Generation區(qū)滿了之后將執(zhí)行 GC 操作,該操作稱為:Major GC,耗用的時間也相對較長。

Young Generation和 Old Generation都可以主動觸發(fā) stop-the-world 事件,掛起所有任務,執(zhí)行 GC 操作。被掛起的任務只有在 GC 執(zhí)行完畢后,才會恢復執(zhí)行。

多數(shù)情況下, GC 性能調優(yōu)(GC tuning)就是指降低 stop-the-world 時 GC 執(zhí)行的時間。

圖中還有一塊區(qū)域沒有顯示出來,就是元數(shù)據(jù)空間,

Metaspace所占用的內存空間不是在虛擬機內部,而是在本地內存空間中,這也是與1.7的永久代最大的區(qū)別所在。而元數(shù)據(jù)空間就是上文說到的方法區(qū)存放的東西。

至于為什么還有這樣的區(qū)分:我的理解是方法區(qū)是jvm虛擬機規(guī)范的一種說法,具體的落地實踐在jdk1.7是通過在堆中定義一個永久代來實現(xiàn),jdk1.8是通過在堆外定義的一個元數(shù)據(jù)空間來實現(xiàn)。

為什么jdk1.7的永久區(qū)要被廢除:

官網(wǎng)給出的解釋是:

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沒有永久代,

不需要配置永久代

現(xiàn)實使用中,由于永久代內存經(jīng)常不夠用或發(fā)生內存泄露,爆出異常

java.lang.OutOfMemoryError: PermGen。

基于此,將永久區(qū)廢棄,而改用元空間,改為了使用本地內存空間。

JVM內存分析指令

通過jstat命令進行查看堆內存使用情況

jstat命令可以查看堆內存各部分的使用量,以及加載類的數(shù)量。命令的格式如下:

jstat [-命令選項] [端口號] [間隔時間/毫秒] [查詢次數(shù)]

常用的有三個命令選項

1. -class 查看類加載統(tǒng)計

[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的數(shù)量

Bytes:所占用空間大小

Unloaded:未加載數(shù)量

Bytes:未加載占用空間

Time:時間

2. -compiler 查看編譯統(tǒng)計

[root@hadoop101 ~]# jstat -compiler 3846

Compiled Failed Invalid Time FailedType FailedMethod

2174 0 0 6.38 0

解釋:

Compiled:編譯數(shù)量。

Failed:失敗數(shù)量

Invalid:不可用數(shù)量

Time:時間

FailedType:失敗類型

FailedMethod:失敗的方法

3. -gc 查看垃圾回收統(tǒng)計(十分常用)

[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

解釋:(你會發(fā)現(xiàn)總有一個survivor是空的,這也印證了我上面說到的年輕代的存儲方式)

S0C:第一個Survivor區(qū)的大小(KB)

S1C:第二個Survivor區(qū)的大小(KB)

S0U:第一個Survivor區(qū)的使用大小(KB)

S1U:第二個Survivor區(qū)的使用大小(KB)

EC:Eden區(qū)的大小(KB)

EU:Eden區(qū)的使用大小(KB)

OC:Old區(qū)大小(KB)

OU:Old使用大小(KB)

MC:方法區(qū)大小(KB)

MU:方法區(qū)使用大小(KB)

CCSC:壓縮類空間大小(KB)

CCSU:壓縮類空間使用大小(KB)

YGC:年輕代垃圾回收次數(shù)

YGCT:年輕代垃圾回收消耗時間

FGC:老年代垃圾回收次數(shù)

FGCT:老年代垃圾回收消耗時間

GCT:垃圾回收消耗總時間

通過jmap指令來分析內存溢出

前面通過jstat可以對jvm堆的內存進行統(tǒng)計分析,而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.

查看內存中對象數(shù)量及大小

查看所有對象,包括活躍以及非活躍的

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

[ 數(shù)組,如[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,可以快速查詢到想要看的數(shù)據(jù)

總結

以上是生活随笔為你收集整理的modeler java堆空间,JVM|02内存模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。