最近利用工作之余學(xué)習研究了一下java的內(nèi)存管理機制,在這里記錄總結(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è)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學(xué)習、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。當java程序運行時,java虛擬機會將內(nèi)存劃分為若干個不同的數(shù)據(jù)區(qū)域,這些內(nèi)存區(qū)域創(chuàng)建和銷毀的時間各不相同,所承擔的功能也不相同,他們各司其職,各盡所責。這些區(qū)域的劃分如下圖
運行時數(shù)據(jù)區(qū)主要有五個區(qū),分別是 堆 ,方法區(qū),虛擬機棧,本地方法棧,程序計數(shù)器 ,下面我來一一詳細講解這五個數(shù)據(jù)區(qū)
java堆是java虛擬機管理內(nèi)存中大的一塊,它是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機啟動時創(chuàng)建, 此內(nèi)存的唯一目的就是存放對象實例,幾乎所有的對象實例以及數(shù)組都在堆分配內(nèi)存 。
java虛擬機規(guī)定,java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上連續(xù)即可。在實現(xiàn)時,既可以實現(xiàn)固定大小的,也可以是擴展的,可以 通過配置-Xmx和-Xms來擴展大小 。如果堆中沒有內(nèi)存完成實例分配,并且堆也無法再擴展時,將會拋出 OutOfMemoryError
方法區(qū)也是被所有線程共享的一塊內(nèi)存區(qū)域,在Java虛擬機規(guī)范中,方法區(qū)是堆的邏輯組成部分,但他又被與堆區(qū)分開來,別名稱為Non-Heap,它主要的存儲內(nèi)容有下面幾點
總結(jié)起來就是主要用于存儲已被虛擬機加載的類信息,常量,靜態(tài)變量,編譯器編譯后的代碼等數(shù)據(jù)
這里我在介紹一下常量池,域信息和方法信息
常量池也稱為運行時常量池(Runtime Constant Pool),用于存放編譯期生成的各種字面量和符號引用,它是這個類型用到的常量的一個有序集合,包括
實際的常量(String, Integer, 和Floating point常量)和類型,域和方法的符號引用
。
池中的數(shù)據(jù)項像數(shù)組項一樣,是通過索引訪問的。 因為常量池存儲了一個類類型所使用到的所有類型,域和方法的符號引用,所以它在java程序的動態(tài)鏈接中起了核心的作用
域的相關(guān)信息包括: 域名; 域類型; 域修飾符(public, private, protected,static,final volatile,transient的某個子集)
方法的相關(guān)信息包括: 方法名, 方法的返回類型(或 void), 方法參數(shù)的數(shù)量和類型(有序的),方法的修飾符(public, private, protected, static, final, synchronized, native, abstract的一個子集) ,除了abstract和native方法外,其他方法還有保存方法的 字節(jié)碼(bytecodes)操作數(shù)棧和方法棧幀的局部變量區(qū)的大小 。
java虛擬機規(guī)范對方法區(qū)的限制比較寬松,除了和java堆一樣不需要連續(xù)的內(nèi)存和可以選擇固定大小或者可擴展外,還可以選擇不是實現(xiàn)垃圾收集。垃圾收集行為在方法區(qū)也比較少出現(xiàn),當方法區(qū)無法滿足內(nèi)存分配時,會拋出 OutOfMemoryError
虛擬機棧是線程私有的,它的生命周期與線程相同,當我們start一個線程時,jvm會為當前線程開辟一塊虛擬機棧,當當前線程死亡時,線程的虛擬機棧也會銷毀。
代碼中每個方法在執(zhí)行的同時,都會創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口等信息。每一個方法調(diào)用直至執(zhí)行完成的過程,就對應(yīng)著一個棧幀在虛擬機棧中入棧到出棧的過程。
局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean,byte,char,short,int,float,long,double),對象引用和returnAddreass類型
JVM對這個區(qū)域規(guī)定了兩種異常情況:如果線程請求的棧深度大于虛擬機所允許的深度,將拋出SstackOverFlowError異常;如果虛擬機??梢詣討B(tài)擴展,如果擴展時無法申請到足夠的內(nèi)存,就會拋出OutOfMemoryErro異常
本地方法棧和虛擬機棧的作用是一樣的,只不過本地方法棧是虛擬機執(zhí)行java方法時開辟的棧,而本地方法棧是虛擬機用到Native方法時,開辟的棧。
程序計數(shù)器是一塊較小的內(nèi)存,它可以看作是當前線程的字節(jié)碼的行號指示器。在虛擬機的概念模型里,字節(jié)碼解釋器工作時就是通過改變這個計數(shù)器的值來選取嚇一跳需要執(zhí)行的字節(jié)碼指令,分支,循環(huán),跳轉(zhuǎn),異常處理,線程恢復(fù)等基礎(chǔ)功能。
由于java虛擬機的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實現(xiàn)的,在任何一個確定的時刻,一個處理器都只會執(zhí)行一條線程中的指令。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個獨立的程序計數(shù)器,各線程指尖計數(shù)器互不影響,獨立存儲。
了解了內(nèi)存的數(shù)據(jù)區(qū)域,我們可以進一步了解對象是如何創(chuàng)建的了。這里先通過一張流程圖一窺java的對象創(chuàng)建過程
可以看到,當虛擬機遇到一條new指令時,首先去檢查這個指令的參數(shù)是否能在常量池中定位到一個類的符號引用,并且檢查這個符號引用代表的類是否已經(jīng)加載。如果沒有,則執(zhí)行加載。
加載完成后,便會在堆中為對象分配內(nèi)存,JVM有兩種分配方式 ①指針碰撞,②空閑列表 ,下面我詳細講講這兩種分配方式。
當java堆中內(nèi)存是整齊的,所有用過的內(nèi)存都放一邊,空閑的內(nèi)存放在另一邊,中間放著一個指針座位分界點的指示器,那所分配內(nèi)存就僅僅是把那個指針向空閑空間那邊摞動一段與對象大小相等的距離,這種分配就叫指針碰撞
當Java堆的內(nèi)存并不是完整的,已分配的內(nèi)存和空閑內(nèi)存相互交錯,JVM通過維護一個列表,記錄可用的內(nèi)存塊信息,當分配操作發(fā)生時,從列表中找到一個足夠大的內(nèi)存塊分配給對象實例,并更新列表上的記錄。這種分配方式稱為空閑列表
當JVM所采用的垃圾收集器帶有壓縮整理功能時,java堆是規(guī)整的,這個時候會采用指針碰撞分配內(nèi)存,否則會采用空閑列表分配內(nèi)存。對象創(chuàng)建是一個非常頻繁的行為,進行堆內(nèi)存分配時還需要考慮多線程并發(fā)問題,可能出現(xiàn)正在給對象A分配內(nèi)存,指針或記錄還未更新,對象B又同時分配到原來的內(nèi)存,解決這個問題有兩種方案:
當前標題:java內(nèi)存管理機制剖析(一)-創(chuàng)新互聯(lián)
網(wǎng)頁URL:http://www.rwnh.cn/article34/dcpjpe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、自適應(yīng)網(wǎng)站、網(wǎng)站設(shè)計公司、網(wǎng)站建設(shè)、App設(shè)計、用戶體驗
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容