溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JAVA虛擬機(JVM)中的內(nèi)存的劃分是怎么用的

發(fā)布時間:2020-07-11 09:34:08 來源:億速云 閱讀:243 作者:Leah 欄目:編程語言

今天就跟大家聊聊有關(guān)JAVA虛擬機中的內(nèi)存的劃分是怎么用的,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

我們知道,在C++語言里,如果想使用一個對象,需要對其進行new操作;如果不用這個對象了,需要對其進行delete操作。一旦開發(fā)人員忘記寫delete語句了,就會造成內(nèi)存泄露。【內(nèi)存被對象占用著不還,就叫內(nèi)存泄露?!?/p>

而java就聰明了,它從“手動”進化成了“自動”,把內(nèi)存的控制權(quán)力交給了虛擬機。下面我們就來窺探一下jvm是怎么進行自動內(nèi)存管理的。

JAVA虛擬機(JVM)中的內(nèi)存的劃分是怎么用的

自動內(nèi)存管理分為兩部分

給對象分配內(nèi)存和回收分配給對象的內(nèi)存。在本篇我們說說前者,也就是內(nèi)存劃分和內(nèi)存分配。下篇再說GC(垃圾回收)。

1、內(nèi)存劃分

我們來看看虛擬機內(nèi)存里都有什么東西。JVM的內(nèi)存區(qū)域大致分為Class文件、類裝載子系統(tǒng)、運行時數(shù)據(jù)區(qū)、執(zhí)行引擎。今天我們只說說運行時數(shù)據(jù)區(qū)。【這張圖是基于JDK7的。JDK7以前,常量池是存放在方法區(qū)的。從JDK7以后,常量池放到了堆中。】

JAVA虛擬機(JVM)中的內(nèi)存的劃分是怎么用的

線程公有

在運行時數(shù)據(jù)區(qū)中,方法區(qū)和堆是屬于線程公有的,也就是這兩塊區(qū)域是“循環(huán)利用”的,所以要對其進行垃圾回收。其是在虛擬機啟動時創(chuàng)建。

線程私有

虛擬機棧、本地方法棧、程序計數(shù)器是屬于線程私有的,其與線程“同生死”,屬于“一次性”的,所以不用對其進行垃圾回收。

(一)方法區(qū)

存儲已被虛擬機加載的類信息,常量,靜態(tài)變量,即時編譯器編譯后的代碼等數(shù)據(jù)。
其中有一個運行時常量池。其存儲的是Class文件中描述的符號引用,直接引用。在編譯期和運行期都可以將新的常量放入此池子中。

(2) 堆

概念:如果說棧解決的是程序運行問題,即程序如何處理數(shù)據(jù);則堆解決的是數(shù)據(jù)存儲問題,即數(shù)據(jù)怎么放,放在哪。

特點:

a、堆是虛擬機內(nèi)存中最大的一塊,大概占內(nèi)存的四分之三。比如一個32位windows平臺中每個進程有2GB的內(nèi)存,則一般將1.5GB的內(nèi)存劃分給堆??梢姸训乃伎臻g之大。
b、可處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可。

作用:

存放對象實例,幾乎所有的對象實例都在這里分配內(nèi)存。

分類:

從內(nèi)存回收的角度看,分為新生代和老年代。
從內(nèi)存分配的角度看,可劃分出多個線程私有的分配緩沖區(qū)。

(3)虛擬機棧

虛擬機棧里面存儲的是棧幀,棧幀里面存儲的是局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口等信息。

JAVA虛擬機(JVM)中的內(nèi)存的劃分是怎么用的

棧中的棧幀

每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀,一個方法從調(diào)用到執(zhí)行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。

棧幀中的局部變量表

存放的是編譯期可知的各種基本數(shù)據(jù)類型,對象引用,returnAddress類型。所以其所需的內(nèi)存空間在編譯期間就能完成分配,在運行期間不會改變其大小。

在分配基本數(shù)據(jù)類型所占的空間時,除了64位的long和double類型的數(shù)據(jù)會占用2個局部變量空間,其余的數(shù)據(jù)類型只占用1個。

(4)本地方法棧

本地方法棧和虛擬機棧的作用是相同的,只不過虛擬機棧執(zhí)行的是java方法,本地方法棧執(zhí)行的是Native方法。
java方法就是開發(fā)人員寫的java代碼,Native方法就是一個java調(diào)用非java代碼的接口。

(5)程序計數(shù)器

程序計數(shù)器中存放的是當前線程所執(zhí)行的字節(jié)碼的行號。jvm工作時,就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令。

2、內(nèi)存分配

這部分我們說說對象在java堆中是如何分配,布局和訪問的,以及內(nèi)存分配的原則。

對象的創(chuàng)建

我們用new來創(chuàng)建對象,來看看系統(tǒng)運行到new時,虛擬機在干什么。此時的類就像一塊肉,他要經(jīng)過層層安檢,才能到達人類的飯桌。第一步:查看在常量池中是否有對應的符號引用?!驹诜椒▍^(qū)中進行】

第二步:查看此類是否被加載,解析和初始化過?!驹诜椒▍^(qū)中進行】

第三步:領取新生對象的內(nèi)存。有兩種方式:指針碰撞和空閑列表?!驹诙阎羞M行】

第四步:將分配到的內(nèi)存空間初始化為零值。

第五步:對對象進行必要的設置,比如其是哪個類的實例,對象的哈希碼之類的。這些信息存放在對象的對象頭之中

第六步:如果java代碼中對對象進行了賦初值,則會進行第六步:執(zhí)行< init >方法。此方法的作用就是對對象進行初始化。

對象的內(nèi)存布局

對象在內(nèi)存中的存儲布局分為3部分:對象頭+實例數(shù)據(jù)+對齊填充

對象頭

對象頭里面有兩部分信息:

(1)運行時數(shù)據(jù),包括哈希碼,GC分代年齡,鎖狀態(tài)標志等。

(2)類型指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。

實例數(shù)據(jù)

實例數(shù)據(jù)中存放的是代碼中定義的各種類型的字段內(nèi)容。

對齊填充

對齊填充起的是占位符的作用,不是必然存在的。其只要保證對象的大小是8字節(jié)的整數(shù)倍即可。

對象的訪問定位

建立完對象后,我們就可以使用對象了。在使用時,怎么才能找到想找的對象?有兩種方式:句柄和直接指針

句柄:

句柄訪問就是在java堆中劃分出一塊內(nèi)存來作為句柄池,句柄中包含了對象實例數(shù)據(jù)和類型數(shù)據(jù)各自具體的地址信息。

JAVA虛擬機(JVM)中的內(nèi)存的劃分是怎么用的

直接指針:

直接指針之所以“直接”,是因為它去除了句柄這個中介。所以在速度上比句柄快。在HotSpot虛擬機中,使用的是這種方式。

JAVA虛擬機(JVM)中的內(nèi)存的劃分是怎么用的

說完了對象在java堆中是如何分配,布局和訪問的,接下來我們說說內(nèi)存分配的原則

內(nèi)存分配的原則:

JAVA虛擬機(JVM)中的內(nèi)存的劃分是怎么用的

堆大致分為新生代,老年代,永久代。對象的內(nèi)存分配主要分配在新生代的Eden區(qū),少數(shù)情況下會直接分配到老年代中。分配的規(guī)則不是100%固定的,取決于垃圾收集器組合和參數(shù)設置等。下面有幾條分配原則可供參考。

(1)對象優(yōu)先在Eden分配。

(2)大對象直接進入老年代。

(3)長期存活的對象將進入老年代。

(4)動態(tài)對象年齡判定。

(5)空間分配擔保。

看完上述內(nèi)容,你們對JAVA虛擬機中的內(nèi)存的劃分是怎么用的有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI