教你JVM怎么使用native memory
JRE如何使用native存儲(chǔ)
今天看到一篇特別好的文章,翻譯其中一小段Understanding how the JVM uses native memory
Runtime環(huán)境提供了被某些未知的用戶代碼驅(qū)動(dòng)的能力,這使runtime在任何情況下都能使用合適的資源。每一個(gè)JVM管理的java應(yīng)用的行為都會(huì)潛在的影響JVM所能提供的運(yùn)行時(shí)環(huán)境。這一節(jié)我們討論為什么Java應(yīng)用會(huì)消耗native存儲(chǔ)
Java堆和GC
Java的堆是用來存儲(chǔ)分配對(duì)象的一塊內(nèi)存,大多數(shù)的JVM有一塊邏輯堆內(nèi)存,也有少數(shù)的JVM實(shí)現(xiàn)了多塊堆存儲(chǔ)。一個(gè)物理內(nèi)存可以基于GC被分配成多塊邏輯上的內(nèi)存。
The Just-in-time (JIT) compiler
JIT編譯器會(huì)把java字節(jié)碼編譯成運(yùn)行時(shí)可以直接運(yùn)行的機(jī)器碼,這極大的提升了JRE運(yùn)行速度,使Java代碼運(yùn)行比肩native code。
字節(jié)碼編譯會(huì)使用native內(nèi)存(同理,一些像GCC這樣的編譯器也需要內(nèi)存去run),但是JIT的輸入(字節(jié)碼)輸出(機(jī)器碼)都必須存儲(chǔ)在native內(nèi)存中。所以包含很多JIT-compiled的方法的應(yīng)用相對(duì)來說更占用native內(nèi)存。
Classes and classloaders
Java程序由定義了對(duì)象和方法邏輯的類組成,可能是Java運(yùn)行時(shí)的庫(比如java.lang.String),也可能是三方庫。這些class在被使用的時(shí)候會(huì)被加載進(jìn)來并被存儲(chǔ)在內(nèi)存里面。
class如何被存儲(chǔ)不同JVM的實(shí)現(xiàn)相差極大。Sun JDK存儲(chǔ)在永生帶(PermGen),IBM從Java5開始為每個(gè)classloader開辟native內(nèi)存并將它們存儲(chǔ)在那里。具體的存儲(chǔ)位置需要查看實(shí)現(xiàn)的文檔。
顯而易見的是,用更多的類會(huì)消耗更多的內(nèi)存。(這意味著你的native內(nèi)存消耗會(huì)持續(xù)增加,或者明確的開辟一塊內(nèi)存,像PermGen,去容納所有的class),需要注意的是不止是你的應(yīng)用的class需要存儲(chǔ),frameworks,application servers,三方庫,JRE這里面的class在被用到的時(shí)候都會(huì)被加載并存儲(chǔ)進(jìn)來。
JRE允許卸載class去回收空間,但是這僅僅是在內(nèi)存嚴(yán)重不足的情況下。不可能僅僅卸載一個(gè)單獨(dú)的class文件,而是卸載classloader,和它加載進(jìn)來的所有class,一個(gè)classloader僅僅會(huì)在以下情況下被卸載:
- Java堆中不包含任何代表此classloader的java.lang.ClassLoader對(duì)象的應(yīng)引用
- Java堆中不包含任何代表由此classloader加載進(jìn)來的類的java.lang.Class對(duì)象的引用
- Java堆中沒有任何被此classloader加載進(jìn)來的對(duì)象存活。
JNI
JNI允許本地代碼和java代碼相互調(diào)用。JRE嚴(yán)重依賴JNI代碼去實(shí)現(xiàn)文件和網(wǎng)絡(luò)這些類庫的功能,一個(gè)JNI應(yīng)用能以三種方式增加JRE的native內(nèi)存
- JNI應(yīng)用的native代碼會(huì)被編譯進(jìn)一個(gè)so動(dòng)態(tài)鏈接庫,運(yùn)行時(shí)會(huì)被加載到可執(zhí)行的地址空間呢,大型native應(yīng)用程序只需加載就可占據(jù)進(jìn)程地址空間的很大一部分。
- native代碼必須跟JVM共享內(nèi)存,任何native代碼分配或者映射所需要的native內(nèi)存都需要占用JVM的內(nèi)存。
- 某些JNI方法可以使用native作為他們正常操作的一部分,比如GetTypeArrayElements或者GetTypeArrayRegion方法都可以拷貝Java堆內(nèi)存到到native內(nèi)存供native代碼使用。以這種方式訪問大塊的Java堆內(nèi)存相應(yīng)的會(huì)占用大量的native內(nèi)存
NIO
NIO是java1.4之后添加的API,基于管道和緩存,以一種新的方式實(shí)現(xiàn)IO操作。除了基于堆的I/O,NIO還添加了基于native內(nèi)存的direct ByteBuffer(通過java.nio.ByteBuffer.allocateDirect()方法分配)。Direct ByteBuffers可以直接調(diào)用系統(tǒng)庫的方法去實(shí)現(xiàn)I/O操作,這會(huì)顯示提升在某些場(chǎng)景下的執(zhí)行效率,因?yàn)槟鼙苊庠贘ava堆和native堆之間拷貝數(shù)據(jù)。
我們可能會(huì)疑惑direct ByteBuffer申請(qǐng)的內(nèi)存到底存在哪里,應(yīng)用仍然用的是Java堆里面的對(duì)象去完成I/O操作,但是持有數(shù)據(jù)的緩存仍然存在native內(nèi)存中 -Java堆的對(duì)象只是持有了一個(gè)native堆緩存的引用。一個(gè)non-direct ByteBuffer則是直接在Java堆中存儲(chǔ)了byte[]數(shù)組。
Memory topology for direct and non-direct java.nio.ByteBuffers
Java堆發(fā)生GC的時(shí)候同樣會(huì)對(duì)Direct ByteBuffer數(shù)據(jù)執(zhí)行清除native緩存操作,GC僅僅會(huì)在Java堆中已經(jīng)滿了,不支持新的堆空間分配或者程序手動(dòng)調(diào)用GC(不建議手動(dòng)調(diào)用GC)的情況下發(fā)生。
還有一種情況,native內(nèi)存已經(jīng)滿了,又有代碼來請(qǐng)求native內(nèi)存,但是這個(gè)時(shí)候Java堆還沒有達(dá)到GC的條件,所以并不會(huì)發(fā)生GC。(也就是說native內(nèi)存的GC完全依賴Java堆的GC,反之如果native需要GC了但是堆沒有GC的需求的則不會(huì)引發(fā)GC)
Threads
應(yīng)用的每一個(gè)線程都需要內(nèi)存去儲(chǔ)存它的棧(這塊內(nèi)存用來存儲(chǔ)本地變量表和保存狀態(tài)),每一個(gè)Java線程都需要棧去執(zhí)行,根據(jù)實(shí)現(xiàn),Java線程可以具有單獨(dú)的native和Java棧。除了堆??臻g之外,每個(gè)線程還需要一些native內(nèi)存用于thread-local存儲(chǔ)和內(nèi)部數(shù)據(jù)結(jié)構(gòu)。
堆棧大小因Java實(shí)現(xiàn)和架構(gòu)而異。某些實(shí)現(xiàn)允許您指定Java線程的堆棧大小。通常在256KB和756KB之間的值。
盡管每個(gè)線程使用的內(nèi)存量非常小,但對(duì)于具有數(shù)百個(gè)線程的應(yīng)用程序,線程堆棧的總內(nèi)存使用量可能很大。運(yùn)行具有比可用處理器多的線程來運(yùn)行它們的應(yīng)用程序通常是低效的,并且可能導(dǎo)致性能低下以及增加的內(nèi)存使用。
以上就是教你JVM怎么使用native memory的詳細(xì)內(nèi)容,更多關(guān)于JVM使用native memory的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
VScode?隱藏大量無用的文件比如在看Linux?kernel或boot時(shí)候
這篇文章主要介紹了VScode?隱藏大量無用的文件比如在看Linux?kernel或boot時(shí)候,VScode 工程創(chuàng)建先在 Ubuntu 下編譯一下 uboot,然后將編譯后的 uboot 文件夾復(fù)制到 windows 下,并創(chuàng)建VScode 工程,需要的朋友可以參考下2022-10-10將Git存儲(chǔ)庫克隆到本地IntelliJ IDEA項(xiàng)目中的詳細(xì)教程
這篇文章主要介紹了將Git存儲(chǔ)庫克隆到本地IntelliJ IDEA項(xiàng)目中的詳細(xì)教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10手把手教你將Vim改裝成一個(gè)IDE編程環(huán)境(圖文) 吳垠
這篇文章主要介紹了手把手教你將Vim改裝成一個(gè)IDE編程環(huán)境(圖文) 吳垠 ,需要的朋友可以參考下2016-01-01分享VSCOCE遠(yuǎn)程連接服務(wù)器的一次錯(cuò)誤記錄(推薦)
這篇文章主要介紹了VSCOCE遠(yuǎn)程連接服務(wù)器的一次錯(cuò)誤記錄,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04