JVM 堆外內(nèi)存查看方法
概述
- 是否曾經(jīng)想過(guò)為什么Java應(yīng)用程序通過(guò)眾所周知的*-Xms和-Xmx調(diào)整標(biāo)志消耗的內(nèi)存比指定的數(shù)量大得多 ?由于各種原因和可能的優(yōu)化,JVM可能會(huì)分配額外的本機(jī)內(nèi)存。這些額外的分配最終可能使消耗的內(nèi)存超出-Xmx* 限制。
- 在本教程中,我們將枚舉JVM中本機(jī)內(nèi)存分配的一些常見(jiàn)來(lái)源,以及它們的大小調(diào)整標(biāo)志,然后學(xué)習(xí)如何使用本機(jī)內(nèi)存跟蹤來(lái)監(jiān)視它們。
本機(jī)分配
-
通常,堆是Java應(yīng)用程序中最大的內(nèi)存消耗者,但是還有其他一些。**除了堆之外,JVM從本地內(nèi)存中分配了相當(dāng)大的塊來(lái)維護(hù)其類元數(shù)據(jù),應(yīng)用程序代碼,由JIT生成的代碼,內(nèi)部數(shù)據(jù)結(jié)構(gòu)等。**在以下各節(jié)中,我們將探討其中的一些分配。
-
-
可以看到整個(gè)memory主要包含了Java Heap、Class、Thread、Code、GC、Compiler、Internal、Other、Symbol、Native Memory Tracking、Arena Chunk這幾部分;其中reserved表示應(yīng)用可用的內(nèi)存大小,committed表示應(yīng)用正在使用的內(nèi)存大小
-
Java Heap部分表示heap內(nèi)存目前占用了463MB;
-
Class部分表示已經(jīng)加載的classes個(gè)數(shù)為8801,其metadata占用了50MB;
-
Thread部分表示目前有225個(gè)線程,占用了27MB;
-
Code部分表示JIT生成的或者緩存的instructions占用了17MB;
-
GC部分表示目前已經(jīng)占用了15MB的內(nèi)存空間用于幫助GC;
-
Compiler部分表示compiler生成code的時(shí)候占用了26MB;
-
Internal部分表示命令行解析、JVMTI等占用了5MB;
-
Other部分表示尚未歸類的占用了2MB;
-
Symbol部分表示諸如string table及constant pool等symbol占用了10MB;
-
Native Memory Tracking部分表示該功能自身占用了5MB;
-
Arena Chunk部分表示arena chunk占用了63MB
-
一個(gè)arena表示使用malloc分配的一個(gè)memory chunk,這些chunks可以被其他subsystems做為臨時(shí)內(nèi)存使用,比如pre-thread的內(nèi)存分配,它的內(nèi)存釋放是成bulk的
元空間 Class
- 為了維護(hù)有關(guān)已加載類的某些元數(shù)據(jù),JVM使用了稱為*Metaspace*的專用非堆區(qū)域。在Java 8之前,等效項(xiàng)稱為PermGen或Permanent Generation。Metaspace或PermGen包含有關(guān)已加載類的元數(shù)據(jù),而不是包含在堆中的有關(guān)它們的實(shí)例的元數(shù)據(jù)。
- 這里重要的是,由于元空間是堆外數(shù)據(jù)區(qū)域,因此堆大小調(diào)整配置不會(huì)影響元空間的大小。為了限制元空間的大小,我們使用其他調(diào)整標(biāo)志:
- -XX:MetaspaceSize和-XX:MaxMetaspaceSize設(shè)置最小和最大元空間大小
- 在Java 8之前,使用*-XX:PermSize和-XX:MaxPermSize*來(lái)設(shè)置最小和最大PermGen大小
線程數(shù) Thread
- JVM中最消耗內(nèi)存的數(shù)據(jù)區(qū)域之一是堆棧,它與每個(gè)線程同時(shí)創(chuàng)建。堆棧存儲(chǔ)局部變量和部分結(jié)果,在方法調(diào)用中起著重要作用。
- 默認(rèn)的線程堆棧大小取決于平臺(tái),但是在大多數(shù)現(xiàn)代的64位操作系統(tǒng)中,大約為1 MB。此大小可通過(guò)*-Xss *調(diào)整標(biāo)志進(jìn)行配置。
- 與其他數(shù)據(jù)區(qū)域相比,當(dāng)對(duì)線程數(shù)沒(méi)有限制時(shí),分配給堆棧的總內(nèi)存實(shí)際上是不受限制的。 還值得一提的是,JVM本身需要一些線程來(lái)執(zhí)行其內(nèi)部操作,例如GC或即時(shí)編譯。
代碼緩存 Code
- 為了在不同平臺(tái)上運(yùn)行JVM字節(jié)碼,需要將其轉(zhuǎn)換為機(jī)器指令。在執(zhí)行程序時(shí),JIT編譯器負(fù)責(zé)此編譯。
- JVM將字節(jié)碼編譯為匯編指令時(shí),會(huì)將這些指令存儲(chǔ)在稱為*代碼緩存***的特殊非堆數(shù)據(jù)區(qū)域中 。 可以像JVM中的其他數(shù)據(jù)區(qū)域一樣管理代碼緩存。-XX:InitialCodeCacheSize **和 **-XX:ReservedCodeCacheSize **調(diào)諧標(biāo)志確定用于代碼高速緩存中的初始和最大可能大小。
垃圾收集 GC
- JVM附帶了幾種GC算法,每種算法都適合不同的用例。所有這些GC算法都有一個(gè)共同的特征:它們需要使用一些堆外數(shù)據(jù)結(jié)構(gòu)來(lái)執(zhí)行任務(wù)。這些內(nèi)部數(shù)據(jù)結(jié)構(gòu)消耗更多的本機(jī)內(nèi)存。
Symbols
- 讓我們從字符串開(kāi)始 , 它是應(yīng)用程序和庫(kù)代碼中最常用的數(shù)據(jù)類型之一。由于它們無(wú)處不在,因此它們通常占據(jù)堆的很大一部分。如果大量的這些字符串包含相同的內(nèi)容,那么堆的很大一部分將被浪費(fèi)。
- 為了節(jié)省一些堆空間,我們可以存儲(chǔ)每個(gè)String的一個(gè)版本, 并讓其他版本引用存儲(chǔ)的版本。 此過(guò)程稱為字符串實(shí)習(xí)。由于JVM只能內(nèi)生 編譯時(shí)間字符串常量,因此 我們可以對(duì)要內(nèi)生的字符串手動(dòng)調(diào)用intern() 方法。
- JVM將內(nèi)聯(lián)的字符串存儲(chǔ)在特殊的本機(jī)固定大小的哈希表中,該哈希表稱為String Table,也稱為String Pool。我們可以通過(guò)**-XX:StringTableSize** 調(diào)整標(biāo)志來(lái)配置表的大?。赐皵?shù)) 。
- 除了字符串表外,還有另一個(gè)本機(jī)數(shù)據(jù)區(qū)域,稱為運(yùn)行時(shí)常量池。 JVM使用此池存儲(chǔ)必須在運(yùn)行時(shí)解析的常量,例如編譯時(shí)數(shù)字文字,方法和字段引用。
本機(jī)字節(jié)緩沖區(qū) Native Byte Buffers
- JVM通常是大量本機(jī)分配的可疑對(duì)象,但有時(shí)開(kāi)發(fā)人員也可以直接分配本機(jī)內(nèi)存。最常見(jiàn)的方法是通過(guò)JNI和NIO的直接ByteBuffers進(jìn)行**malloc **調(diào)用 。
Additional Tuning Flags
-
在本節(jié)中,我們針對(duì)不同的優(yōu)化方案使用了少數(shù)JVM調(diào)整標(biāo)志。使用以下技巧,我們幾乎可以找到與特定概念相關(guān)的所有調(diào)整標(biāo)志:
-
$ java -XX:+PrintFlagsFinal -version | grep <concept>
-
該PrintFlagsFinal打印所有- *XX *在JVM選項(xiàng)。例如,要查找所有與Metaspace相關(guān)的標(biāo)志:
-
$ java -XX:+PrintFlagsFinal -version | grep Metaspace // truncated uintx MaxMetaspaceSize = 18446744073709547520 {product} uintx MetaspaceSize = 21807104 {pd product} // truncated
本機(jī)內(nèi)存跟蹤(NMT)
-
既然我們知道了JVM中本機(jī)內(nèi)存分配的常見(jiàn)來(lái)源,那么該是時(shí)候找出如何監(jiān)視它們了。**首先,我們應(yīng)該使用另一個(gè)JVM調(diào)整標(biāo)志啟用本地內(nèi)存跟蹤:*-XX:NativeMemoryTracking = off | sumary | detail。 ***默認(rèn)情況下,NMT處于關(guān)閉狀態(tài),但我們可以使它查看其觀測(cè)結(jié)果的摘要或詳細(xì)視圖。
-
假設(shè)我們要跟蹤典型的Spring Boot應(yīng)用程序的本機(jī)分配:
-
$ java -XX:NativeMemoryTracking=summary -Xms300m -Xmx300m -XX:+UseG1GC -jar app.jar
-
在這里,我們使用G1作為GC算法,在分配300 MB堆空間的同時(shí)啟用NMT。
即時(shí)快照
-
啟用NMT后,我們可以隨時(shí)使用*jcmd *命令獲取本機(jī)內(nèi)存信息 :
-
$ jcmd <pid> VM.native_memory
-
為了找到JVM應(yīng)用程序的PID,我們可以使用 jps命令:
-
$ jps -l 7858 app.jar // This is our app7899 sun.tools.jps.Jps
-
現(xiàn)在,如果我們將 jcmd *與適當(dāng)?shù)?pid一起使用, *VM.native_memory *將使JVM打印出有關(guān)本機(jī)分配的信息:
-
$ jcmd 7858 VM.native_memory
-
讓我們逐節(jié)分析NMT輸出。
總分配
-
NMT報(bào)告保留和提交的內(nèi)存總量,如下所示:
-
Native Memory Tracking:Total: reserved=1731124KB, committed=448152KB
-
保留的內(nèi)存代表我們的應(yīng)用程序可能使用的內(nèi)存總量。相反,已提交的內(nèi)存等于我們的應(yīng)用程序當(dāng)前正在使用的內(nèi)存量。
-
盡管分配了300 MB的堆,但我們的應(yīng)用程序的總保留內(nèi)存幾乎為1.7 GB,遠(yuǎn)不止于此。同樣,已提交的內(nèi)存大約為440 MB,這又遠(yuǎn)遠(yuǎn)超過(guò)了300 MB。
-
在合計(jì)部分之后,NMT報(bào)告每個(gè)分配源的內(nèi)存分配。因此,讓我們深入探討每個(gè)來(lái)源。
堆
-
NMT按預(yù)期報(bào)告了我們的堆分配:
-
Java Heap (reserved=307200KB, committed=307200KB) (mmap: reserved=307200KB, committed=307200KB)
-
300 MB的保留和提交內(nèi)存,與我們的堆大小設(shè)置匹配。
元空間
-
NMT關(guān)于已加載類的類元數(shù)據(jù)的說(shuō)明如下:
-
Class (reserved=1091407KB, committed=45815KB) (classes #6566) (malloc=10063KB #8519) (mmap: reserved=1081344KB, committed=35752KB)
-
保留了將近1 GB的空間,并有45 MB的空間用于加載6566類。
線程
-
這是關(guān)于線程分配的NMT報(bào)告:
-
Thread (reserved=37018KB, committed=37018KB) (thread #37) (stack: reserved=36864KB, committed=36864KB) (malloc=112KB #190) (arena=42KB #72)
-
總共為37個(gè)線程的堆棧分配了36 MB的內(nèi)存–每個(gè)堆棧幾乎1 MB。JVM在創(chuàng)建時(shí)將內(nèi)存分配給線程,因此保留和提交的分配是相等的。
代碼緩存
-
讓我們看看NMT對(duì)JIT生成和緩存的匯編指令的評(píng)價(jià):
-
Code (reserved=251549KB, committed=14169KB) (malloc=1949KB #3424) (mmap: reserved=249600KB, committed=12220KB)
-
當(dāng)前,將近有13 MB的代碼被緩存,并且該數(shù)量可能會(huì)增加到大約245 MB。
GC
-
這是有關(guān)G1 GC內(nèi)存使用情況的NMT報(bào)告:
-
GC (reserved=61771KB, committed=61771KB) (malloc=17603KB #4501) (mmap: reserved=44168KB, committed=44168KB)
-
我們可以看到,幾乎有60 MB的空間被保留并致力于幫助G1。
-
讓我們看看一個(gè)簡(jiǎn)單得多的GC(例如串行GC)的內(nèi)存使用情況:
-
$ java -XX:NativeMemoryTracking=summary -Xms300m -Xmx300m -XX:+UseSerialGC -jar app.jar
-
串行GC幾乎不使用1 MB:
-
GC (reserved=1034KB, committed=1034KB) (malloc=26KB #158) (mmap: reserved=1008KB, committed=1008KB)
-
顯然,我們不應(yīng)該僅僅因?yàn)閮?nèi)存使用率就選擇了GC算法,因?yàn)榇蠫C的“停滯不前”性質(zhì)可能會(huì)導(dǎo)致性能下降。
符號(hào)Symbol
-
這是有關(guān)符號(hào)分配的NMT報(bào)告,例如字符串表和常量池:
-
Symbol (reserved=10148KB, committed=10148KB) (malloc=7295KB #66194) (arena=2853KB #1)
-
將近10 MB分配給符號(hào)。
隨著時(shí)間的NMT
-
NMT使我們能夠跟蹤內(nèi)存分配如何隨時(shí)間變化。**首先,我們應(yīng)將應(yīng)用程序的當(dāng)前狀態(tài)標(biāo)記為基線:
-
$ jcmd <pid> VM.native_memory baseline
-
然后,過(guò)一會(huì)兒,我們可以將當(dāng)前內(nèi)存使用量與該基準(zhǔn)進(jìn)行比較:
-
$ jcmd <pid> VM.native_memory summary.diff
-
NMT使用+和–符號(hào)將告訴我們?cè)诖似陂g內(nèi)存使用量如何變化:
-
Total: reserved=1771487KB +3373KB, committed=491491KB +6873KB- Java Heap (reserved=307200KB, committed=307200KB) (mmap: reserved=307200KB, committed=307200KB) - Class (reserved=1084300KB +2103KB, committed=39356KB +2871KB)// Truncated
-
保留和提交的總內(nèi)存分別增加了3 MB和6 MB??梢院苋菀椎匕l(fā)現(xiàn)內(nèi)存分配中的其他波動(dòng)。
詳細(xì)的NMT
- NMT可以提供有關(guān)整個(gè)內(nèi)存空間映射的非常詳細(xì)的信息。要啟用此詳細(xì)報(bào)告,我們應(yīng)該使用*-XX:NativeMemoryTracking = detail *調(diào)整標(biāo)志。
-----------------------------------------------------------------------------------
offer突擊訓(xùn)練營(yíng)簡(jiǎn)介:
1:針對(duì)不知道怎么面試,面試沒(méi)有信心的小伙伴,我們會(huì)給你一個(gè)offer保障。
2:我們會(huì)監(jiān)督你15-20天內(nèi)把面試體系技術(shù)點(diǎn)掌握至少7成,這樣足夠你去找到滿意的工作了。
3:我們是面向面試學(xué)習(xí)指導(dǎo),不會(huì)帶你們?nèi)?xiě)代碼,會(huì)把項(xiàng)目真實(shí)開(kāi)發(fā)的迭代過(guò)程和技術(shù)細(xì)節(jié)如何實(shí)現(xiàn)業(yè)務(wù)功能都詳細(xì)教清楚,你能在面試中流暢表達(dá)清楚就行了,項(xiàng)目經(jīng)驗(yàn)?zāi)悴挥脫?dān)心(技術(shù)老師提供的真實(shí)項(xiàng)目經(jīng)驗(yàn)肯定拿的出手),自己學(xué)和別人帶著系統(tǒng)學(xué),效率完全不一樣。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-721863.html
詳情請(qǐng)點(diǎn)擊這里:offer突擊訓(xùn)練營(yíng),給你一個(gè)offer的保障,求職跳槽的看過(guò)來(lái)!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-721863.html
到了這里,關(guān)于JVM 堆外內(nèi)存查看方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!