java內(nèi)存管理機(jī)制剖析(一)-創(chuàng)新互聯(lián)

最近利用工作之余學(xué)習(xí)研究了一下java的內(nèi)存管理機(jī)制,在這里記錄總結(jié)一下。

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),武安企業(yè)網(wǎng)站建設(shè),武安品牌網(wǎng)站建設(shè),網(wǎng)站定制,武安網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,武安網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。

1.1 java內(nèi)存區(qū)域

當(dāng)java程序運(yùn)行時,java虛擬機(jī)會將內(nèi)存劃分為若干個不同的數(shù)據(jù)區(qū)域,這些內(nèi)存區(qū)域創(chuàng)建和銷毀的時間各不相同,所承擔(dān)的功能也不相同,他們各司其職,各盡所責(zé)。這些區(qū)域的劃分如下圖
java內(nèi)存管理機(jī)制剖析(一)

運(yùn)行時數(shù)據(jù)區(qū)主要有五個區(qū),分別是 堆 ,方法區(qū),虛擬機(jī)棧,本地方法棧,程序計(jì)數(shù)器 ,下面我來一一詳細(xì)講解這五個數(shù)據(jù)區(qū)

java堆是java虛擬機(jī)管理內(nèi)存中大的一塊,它是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動時創(chuàng)建, 此內(nèi)存的唯一目的就是存放對象實(shí)例,幾乎所有的對象實(shí)例以及數(shù)組都在堆分配內(nèi)存

java虛擬機(jī)規(guī)定,java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上連續(xù)即可。在實(shí)現(xiàn)時,既可以實(shí)現(xiàn)固定大小的,也可以是擴(kuò)展的,可以 通過配置-Xmx和-Xms來擴(kuò)展大小 。如果堆中沒有內(nèi)存完成實(shí)例分配,并且堆也無法再擴(kuò)展時,將會拋出 OutOfMemoryError

方法區(qū)

方法區(qū)也是被所有線程共享的一塊內(nèi)存區(qū)域,在Java虛擬機(jī)規(guī)范中,方法區(qū)是堆的邏輯組成部分,但他又被與堆區(qū)分開來,別名稱為Non-Heap,它主要的存儲內(nèi)容有下面幾點(diǎn)

  • 類型的完整有效名
  • 類型直接父類的完整有效名
  • 類型的修飾符(public,abstract,final的某個子集)
  • 類型的常量池
  • 域(Field)信息
  • 方法(Method)信息
  • 除了常量外的所有靜態(tài)(static)變量

總結(jié)起來就是主要用于存儲已被虛擬機(jī)加載的類信息,常量,靜態(tài)變量,編譯器編譯后的代碼等數(shù)據(jù)

這里我在介紹一下常量池,域信息和方法信息

—-常量池

常量池也稱為運(yùn)行時常量池(Runtime Constant Pool),用于存放編譯期生成的各種字面量和符號引用,它是這個類型用到的常量的一個有序集合,包括 實(shí)際的常量(String, Integer, 和Floating point常量)和類型,域和方法的符號引用 。
池中的數(shù)據(jù)項(xiàng)像數(shù)組項(xiàng)一樣,是通過索引訪問的。 因?yàn)槌A砍卮鎯α艘粋€類類型所使用到的所有類型,域和方法的符號引用,所以它在java程序的動態(tài)鏈接中起了核心的作用

—-域(Field)信息

域的相關(guān)信息包括: 域名; 域類型; 域修飾符(public, private, protected,static,final volatile,transient的某個子集)

—-方法(Method)信息

方法的相關(guān)信息包括: 方法名, 方法的返回類型(或 void), 方法參數(shù)的數(shù)量和類型(有序的),方法的修飾符(public, private, protected, static, final, synchronized, native, abstract的一個子集) ,除了abstract和native方法外,其他方法還有保存方法的 字節(jié)碼(bytecodes)操作數(shù)棧和方法棧幀的局部變量區(qū)的大小 。

java虛擬機(jī)規(guī)范對方法區(qū)的限制比較寬松,除了和java堆一樣不需要連續(xù)的內(nèi)存和可以選擇固定大小或者可擴(kuò)展外,還可以選擇不是實(shí)現(xiàn)垃圾收集。垃圾收集行為在方法區(qū)也比較少出現(xiàn),當(dāng)方法區(qū)無法滿足內(nèi)存分配時,會拋出 OutOfMemoryError

虛擬機(jī)棧

虛擬機(jī)棧是線程私有的,它的生命周期與線程相同,當(dāng)我們start一個線程時,jvm會為當(dāng)前線程開辟一塊虛擬機(jī)棧,當(dāng)當(dāng)前線程死亡時,線程的虛擬機(jī)棧也會銷毀。

代碼中每個方法在執(zhí)行的同時,都會創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口等信息。每一個方法調(diào)用直至執(zhí)行完成的過程,就對應(yīng)著一個棧幀在虛擬機(jī)棧中入棧到出棧的過程。

局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean,byte,char,short,int,float,long,double),對象引用和returnAddreass類型

JVM對這個區(qū)域規(guī)定了兩種異常情況:如果線程請求的棧深度大于虛擬機(jī)所允許的深度,將拋出SstackOverFlowError異常;如果虛擬機(jī)??梢詣討B(tài)擴(kuò)展,如果擴(kuò)展時無法申請到足夠的內(nèi)存,就會拋出OutOfMemoryErro異常

本地方法棧

本地方法棧和虛擬機(jī)棧的作用是一樣的,只不過本地方法棧是虛擬機(jī)執(zhí)行java方法時開辟的棧,而本地方法棧是虛擬機(jī)用到Native方法時,開辟的棧。

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

程序計(jì)數(shù)器是一塊較小的內(nèi)存,它可以看作是當(dāng)前線程的字節(jié)碼的行號指示器。在虛擬機(jī)的概念模型里,字節(jié)碼解釋器工作時就是通過改變這個計(jì)數(shù)器的值來選取嚇一跳需要執(zhí)行的字節(jié)碼指令,分支,循環(huán),跳轉(zhuǎn),異常處理,線程恢復(fù)等基礎(chǔ)功能。

由于java虛擬機(jī)的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實(shí)現(xiàn)的,在任何一個確定的時刻,一個處理器都只會執(zhí)行一條線程中的指令。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個獨(dú)立的程序計(jì)數(shù)器,各線程指尖計(jì)數(shù)器互不影響,獨(dú)立存儲。

1.2 對象創(chuàng)建

了解了內(nèi)存的數(shù)據(jù)區(qū)域,我們可以進(jìn)一步了解對象是如何創(chuàng)建的了。這里先通過一張流程圖一窺java的對象創(chuàng)建過程
java內(nèi)存管理機(jī)制剖析(一)
可以看到,當(dāng)虛擬機(jī)遇到一條new指令時,首先去檢查這個指令的參數(shù)是否能在常量池中定位到一個類的符號引用,并且檢查這個符號引用代表的類是否已經(jīng)加載。如果沒有,則執(zhí)行加載。

加載完成后,便會在堆中為對象分配內(nèi)存,JVM有兩種分配方式 ①指針碰撞,②空閑列表 ,下面我詳細(xì)講講這兩種分配方式。

—-指針碰撞

當(dāng)java堆中內(nèi)存是整齊的,所有用過的內(nèi)存都放一邊,空閑的內(nèi)存放在另一邊,中間放著一個指針座位分界點(diǎn)的指示器,那所分配內(nèi)存就僅僅是把那個指針向空閑空間那邊摞動一段與對象大小相等的距離,這種分配就叫指針碰撞

—-空閑列表

當(dāng)Java堆的內(nèi)存并不是完整的,已分配的內(nèi)存和空閑內(nèi)存相互交錯,JVM通過維護(hù)一個列表,記錄可用的內(nèi)存塊信息,當(dāng)分配操作發(fā)生時,從列表中找到一個足夠大的內(nèi)存塊分配給對象實(shí)例,并更新列表上的記錄。這種分配方式稱為空閑列表

當(dāng)JVM所采用的垃圾收集器帶有壓縮整理功能時,java堆是規(guī)整的,這個時候會采用指針碰撞分配內(nèi)存,否則會采用空閑列表分配內(nèi)存。對象創(chuàng)建是一個非常頻繁的行為,進(jìn)行堆內(nèi)存分配時還需要考慮多線程并發(fā)問題,可能出現(xiàn)正在給對象A分配內(nèi)存,指針或記錄還未更新,對象B又同時分配到原來的內(nèi)存,解決這個問題有兩種方案:

  • 1、采用CAS保證數(shù)據(jù)更新操作的原子性;
  • 2、把內(nèi)存分配的行為按照線程進(jìn)行劃分,在不同的空間中進(jìn)行,每個線程在Java堆中預(yù)先分配一個內(nèi)存塊,稱為本地線程分配緩沖(Thread Local Allocation Buffer, TLAB);

當(dāng)前標(biāo)題:java內(nèi)存管理機(jī)制剖析(一)-創(chuàng)新互聯(lián)
網(wǎng)頁URL:http://muchs.cn/article34/dcpjpe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、自適應(yīng)網(wǎng)站、網(wǎng)站設(shè)計(jì)公司網(wǎng)站建設(shè)、App設(shè)計(jì)、用戶體驗(yàn)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營