日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

JVM內(nèi)存模型

概述

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

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

程序計(jì)數(shù)器

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

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

因?yàn)榫€程在多線程的情況下,需要進(jìn)行來回的切換線程,所以就需要有一個(gè)程序計(jì)數(shù)器來記錄下當(dāng)前線程跳轉(zhuǎn)之前執(zhí)行到的地方的位置,所以這塊區(qū)域只能是線程私有的。

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

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

虛擬機(jī)棧

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

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

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

譬如我們要對(duì)i進(jìn)行i++,步驟如下:

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

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

棧幀與局部變量表都是在編譯期間確定的內(nèi)存空間,運(yùn)行期間不會(huì)改變。

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

線程請(qǐng)求的棧深度大于虛擬機(jī)允許的棧深度,將拋出StackOverflowError。

虛擬機(jī)棧空間可以動(dòng)態(tài)擴(kuò)展,當(dāng)動(dòng)態(tài)擴(kuò)展是無法申請(qǐng)到足夠的空間時(shí),拋出OutOfMemory異常。

本地方法棧

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

方法區(qū)

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

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

堆是一塊線程共享的,多線程的情況下需要線程同步機(jī)制,它的目的是存放對(duì)象實(shí)例。

jdk1.8的堆內(nèi)存模型如下:

年輕代Young Generation:

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

后將未被GC回收的對(duì)象放入移動(dòng)到 From Survivor 或 To Survivor 中。

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

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

老年代 Old Generation

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

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

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

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

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

至于為什么還有這樣的區(qū)分:我的理解是方法區(qū)是jvm虛擬機(jī)規(guī)范的一種說法,具體的落地實(shí)踐在jdk1.7是通過在堆中定義一個(gè)永久代來實(shí)現(xiàn),jdk1.8是通過在堆外定義的一個(gè)元數(shù)據(jù)空間來實(shí)現(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而做出的努力,因?yàn)镴Rockit沒有永久代,

不需要配置永久代

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

java.lang.OutOfMemoryError: PermGen。

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

JVM內(nèi)存分析指令

通過jstat命令進(jìn)行查看堆內(nèi)存使用情況

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

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

常用的有三個(gè)命令選項(xiàng)

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

[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:時(shí)間

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

[root@hadoop101 ~]# jstat -compiler 3846

Compiled Failed Invalid Time FailedType FailedMethod

2174 0 0 6.38 0

解釋:

Compiled:編譯數(shù)量。

Failed:失敗數(shù)量

Invalid:不可用數(shù)量

Time:時(shí)間

FailedType:失敗類型

FailedMethod:失敗的方法

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

[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

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

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

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

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

S1U:第二個(gè)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:年輕代垃圾回收消耗時(shí)間

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

FGCT:老年代垃圾回收消耗時(shí)間

GCT:垃圾回收消耗總時(shí)間

通過jmap指令來分析內(nèi)存溢出

前面通過jstat可以對(duì)jvm堆的內(nèi)存進(jìn)行統(tǒng)計(jì)分析,而jmap可以獲取到更加詳細(xì)的內(nèi)容,

如:內(nèi)存使用情況的匯總、對(duì)內(nèi)存溢出的定位與分析。

查看內(nèi)存使用情況

指令格式:jmap -heap 端口號(hào)

[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: # 堆內(nèi)存的配置信息

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: # 堆內(nèi)存的使用情況

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.

查看內(nèi)存中對(duì)象數(shù)量及大小

查看所有對(duì)象,包括活躍以及非活躍的

jmap ‐histo 端口號(hào) | more

查看活躍對(duì)象

jmap ‐histo:live 端口號(hào) | 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+類名 其他對(duì)象

將內(nèi)存使用情況dump到文件中

有些時(shí)候我們需要將jvm當(dāng)前內(nèi)存中的情況dump到文件中,然后對(duì)它進(jìn)行分析,jmap也

是支持dump到文件中的

語法:jmap ‐dump:format=b,file=目標(biāo)文件全路徑 端口號(hào)

[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對(duì)dump文件進(jìn)行分析

我們將jvm的內(nèi)存dump到文件中,這個(gè)文件是一個(gè)二進(jìn)制的文件,不方便查看,這時(shí)我們可以借助于jhat工具進(jìn)行查看。

語法: jhat ‐port 瀏覽器訪問端口號(hào) 文件

[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.

我們可以通過服務(wù)器ip:8081查看

在最后還有一個(gè)OQL的查詢功能,語法類似SQL,可以快速查詢到想要看的數(shù)據(jù)

總結(jié)

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

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