Java內(nèi)存區(qū)域管理詳解
1 關(guān)于自動(dòng)內(nèi)存管理
- Java是由jvm來管理內(nèi)存,包括自動(dòng)分配以及自動(dòng)回收,因此它不容易出現(xiàn)內(nèi)存泄漏和內(nèi)存溢出問題。
- C/C++,由程序員手動(dòng)管理內(nèi)存,手動(dòng)完成:使用前申請(qǐng)內(nèi)存,使用后釋放內(nèi)存。
2 運(yùn)行時(shí)數(shù)據(jù)區(qū)域
Java虛擬機(jī)在執(zhí)行Java程序的過程中會(huì)把它所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域。這些區(qū)域有各自的用途,以及創(chuàng)建和銷毀的時(shí)間。
Java虛擬機(jī)所管理的內(nèi)存 包括以下幾個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域:
2.1 程序計(jì)數(shù)器
- 程序計(jì)數(shù)器(Program Counter Register):存儲(chǔ)當(dāng)前線程所執(zhí)行的字節(jié)碼指令的內(nèi)存地址。字節(jié)碼解釋器工作時(shí)就是通過改變這個(gè)計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令?!?strong>通過PC來尋找下一條要執(zhí)行的指令】。
- 程序計(jì)數(shù)器是線程私有的。cpu通過輪流分配時(shí)間片來執(zhí)行線程,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,顯然每個(gè)線程都需要有一個(gè)獨(dú)立的程序計(jì)數(shù)器。
- 如果線程正在執(zhí)行的是一個(gè)Java方法,PC記錄的是正在執(zhí)行的字節(jié)碼指令的地址;如果正在執(zhí)行的是本地(Native)方法,這個(gè)計(jì)數(shù)器值則應(yīng)為空?!総odo 為什么本地方法時(shí)為空】
2.2 虛擬機(jī)棧
- 虛擬機(jī)棧描述的是Java方法執(zhí)行的線程內(nèi)存模型:每個(gè)方法被執(zhí)行的時(shí)候,jvm會(huì)同步創(chuàng)建一個(gè)棧幀[后續(xù)章節(jié)詳解](Stack Frame)用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)連接、方法出口等信息。
- 虛擬機(jī)棧也是線程私有的,它的生命周期與線程相同。
2.2.1 局部變量表
JDK8之前,對(duì)jvm內(nèi)存的認(rèn)知只停留在:堆內(nèi)存(Heap)和棧內(nèi)存(Stack),而“棧”通常就是指這里講的虛擬機(jī)棧,或者更多的情況下只是指虛擬機(jī)棧中局部變量表部分。
- 局部變量表存儲(chǔ):基本數(shù)據(jù)類型(八種:boolean、byte、char、short、int、 float、long、double)、對(duì)象引用(可能是一個(gè)指向?qū)ο笃鹗?地址的引用指針)和returnAddress 類型(指向了一條字節(jié)碼指令的地址)。
- 局部變量表所需的內(nèi)存空間在編譯期間完成分配,當(dāng)進(jìn)入一個(gè)方法時(shí),這個(gè)方法需要在棧幀中分配多大的局部變量空間是完全確定 的,在方法運(yùn)行期間不會(huì)改變局部變量表的大小?!具@里的大小僅值變量槽的數(shù)量】
- 局部變量表以局部變量槽(Slot)來存儲(chǔ)數(shù)據(jù),其中64位長(zhǎng)度的long和 double類型的數(shù)據(jù)會(huì)占用兩個(gè)變量槽,其余的數(shù)據(jù)類型只占用一個(gè)。(通常一個(gè)槽占據(jù)N個(gè)字節(jié),N大小由不同的虛擬機(jī)實(shí)現(xiàn)決定)。
關(guān)于棧的內(nèi)存數(shù)據(jù)分析,在后續(xù)章節(jié)中會(huì)有更深入分析,在本節(jié)中這里僅引入概念。
2.2.2 操作數(shù)棧
關(guān)于方法調(diào)用時(shí)的進(jìn)棧跟出棧的原理,在《深入理解計(jì)算機(jī)系統(tǒng)》系列筆記的后續(xù)章節(jié)中會(huì)進(jìn)行總結(jié)。
2.3 本地方法棧
- 本地方法棧(Native Method Stacks)與虛擬機(jī)棧作用是非常相似的,其區(qū)別只是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機(jī)使用到的本地(Native) 方法服務(wù)。
- 線程私有的。
2.4 堆
- Java堆(Java Heap)存儲(chǔ)對(duì)象的實(shí)例。
- Java堆是線程共享的,且比較大的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。
- Java堆既可以被實(shí)現(xiàn)成固定大小的,也可以是可擴(kuò)展的,不過當(dāng)前主流的Java虛擬機(jī)都是按照可擴(kuò)展來實(shí)現(xiàn)的(通過參數(shù)-Xmx和-Xms設(shè)定)。
- 可彈性伸縮,但不會(huì)超過設(shè)定的最大容量,如果在Java堆中沒有內(nèi)存完成實(shí)例分配,并且堆也無法再 擴(kuò)展時(shí),Java虛擬機(jī)將會(huì)拋出OutOfMemoryError異常
- Java堆可以處于物理上不連續(xù)的內(nèi)存空間中,但在邏輯上它應(yīng)該 被視為連續(xù)的。
2.5 方法區(qū)
- 方法區(qū)存儲(chǔ)已被虛擬機(jī)加載的class的類型信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼緩存等數(shù)據(jù)。
- 方法區(qū)是線程共享。
- 方法區(qū)不需要連續(xù)的內(nèi)存、可以選擇固定大小或者可擴(kuò)展,甚至還可以選擇不實(shí)現(xiàn)垃圾收集(因?yàn)檫@部分內(nèi)存通常不滿足回收條件)
- 方法區(qū)無法滿足新的內(nèi)存分配需求時(shí),將拋出 OutOfMemoryError異常。
2.5.1 運(yùn)行時(shí)常量池
- 存放編譯期生成的各種字面量與符號(hào)引用
- 運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分
3 直接內(nèi)存
- 首先,直接內(nèi)存(Direct Memory)并不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是《Java虛擬機(jī)規(guī)范》中 定義的內(nèi)存區(qū)域
- 它可能導(dǎo)致OutOfMemoryError異常出現(xiàn),有必要了解。
在JDK 1.4中新加入了NIO(New Input/Output)類,引入了一種基于通道(Channel)與緩沖區(qū) (Buffer)的I/O方式,它可以使用Native函數(shù)庫(kù)直接分配堆外內(nèi)存,然后通過一個(gè)存儲(chǔ)在Java堆里面的 DirectByteBuffer對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場(chǎng)景中顯著提高性能,因?yàn)楸苊饬?在Java堆和Native堆中來回復(fù)制數(shù)據(jù)。
顯然,本機(jī)直接內(nèi)存的分配不會(huì)受到Java堆大小的限制,但是,既然是內(nèi)存,則肯定還是會(huì)受到 本機(jī)總內(nèi)存(包括物理內(nèi)存、SWAP分區(qū)或者分頁(yè)文件)大小以及處理器尋址空間的限制,一般服務(wù) 器管理員配置虛擬機(jī)參數(shù)時(shí),會(huì)根據(jù)實(shí)際內(nèi)存去設(shè)置-Xmx等參數(shù)信息,但經(jīng)常忽略掉直接內(nèi)存,使得 各個(gè)內(nèi)存區(qū)域總和大于物理內(nèi)存限制(包括物理的和操作系統(tǒng)級(jí)的限制),從而導(dǎo)致動(dòng)態(tài)擴(kuò)展時(shí)出現(xiàn) OutOfMemoryError異常。
4 總結(jié)
Java內(nèi)存區(qū)域及其數(shù)據(jù)類別概覽:
到此這篇關(guān)于Java內(nèi)存區(qū)域管理詳解的文章就介紹到這了,更多相關(guān)Java內(nèi)存區(qū)域管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA實(shí)現(xiàn) springmvc的簡(jiǎn)單注冊(cè)登錄功能的示例代碼
這篇文章主要介紹了IDEA實(shí)現(xiàn) springmvc的簡(jiǎn)單注冊(cè)登錄功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06Java 實(shí)戰(zhàn)范例之員工管理系統(tǒng)的實(shí)現(xiàn)
讀萬(wàn)卷書不如行萬(wàn)里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+vue+Springboot+ssm+mysql+maven+redis實(shí)現(xiàn)一個(gè)前后端分離的員工管理系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11解決MyBatis返回結(jié)果類型為Boolean的問題
這篇文章主要介紹了解決MyBatis返回結(jié)果類型為Boolean的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11fastjson轉(zhuǎn)換對(duì)象實(shí)體@JsonProperty不生效問題及解決
這篇文章主要介紹了fastjson轉(zhuǎn)換對(duì)象實(shí)體@JsonProperty不生效問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08簡(jiǎn)單學(xué)習(xí)Java API 設(shè)計(jì)實(shí)踐
API(Application Programming Interface,應(yīng)用程序編程接口)是一些預(yù)先定義的函數(shù),目的是提供應(yīng)用程序與開發(fā)人員基于某軟件或硬件的以訪問一組例程的能力,而又無需訪問源碼,或理解內(nèi)部工作機(jī)制的細(xì)節(jié)。需要的可以了解一下2019-06-06