Java虛擬機在執行Java程序的過程當中會把它所管理的內存劃分爲若干個不一樣的數據區域,本篇文章將會對這些數據區域進行簡略的介紹。
JVM所管理的內存包括的數據區域以下圖所示:算法
根據這張圖咱們來一個個介紹這些數據區域。spa
程序計數器(ProgramCounterRegister)是一塊較小的內存空間,它能夠看做是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型裏(僅是概念模型,各類虛擬機可能會經過一些更高效的方式去實現),字節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都須要依賴這個計數器來完成。線程
每條線程都須要一個獨立的程序計數器,各條線程之間計數器互不影響,獨立存儲,咱們稱這類內存區域爲「線程私有」的內存。對象
若是線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址;若是正在執行的是Native方法,這個計數器值則爲空(Undefined)。生命週期
此內存區域是惟一一個在Java虛擬機規範中沒有規定任何OOM狀況的區域。內存
Java虛擬機棧也是線程私有的,生命週期與線程相同。
虛擬機棧描述的是Java方法執行的內存模型:每一個方法在執行時都會建立一個棧幀用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每一個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機中入棧到出棧的過程。rem
常說的堆和棧中的棧其實指的是Java虛擬機棧或說是虛擬機棧中的局部變量表部分。局部變量表存放了編譯期可知的基本數據類型、對象引用和returnAddress類型(指向了一條字節碼指令的地址)。編譯器
Java虛擬機規範中,對這個區域規定了兩種異常狀況:虛擬機
本地方法棧與虛擬機棧做用相似,區別是虛擬機棧爲虛擬機執行Java方法服務,本地方法棧爲虛擬機使用到的Native方法服務。it
與虛擬機棧同樣,本地方法中也會拋出StackOverflowError和OOM異常
Java堆是被全部線程共享的一塊內存區域,在虛擬機啓動時建立。用來存放對象實例。
從內存回收角度看,因爲如今收集齊基本都採用分代收集算法,因此Java堆還能夠細分爲:新生代和老年代。從內存分配角度看,線程共享的Java堆中額能劃分出多個線程私有的分配緩衝區(TLAB)。
Java堆能夠處於物理上不連續的內存空間中,只要邏輯上連續便可。實現時可固定大小也可擴展大小(-Xmx,-Xms)。若是隊中沒有內存完成實例分配,且堆也沒法再擴展,會拋出OOM異常。
方法區與Java堆同樣,是各個線程共享的內存區域。
用於存儲已被虛擬機加載的類信息、常量、靜態變量、即便編譯器編譯後的代碼數據,別名Non-Heap。
當方法區沒法知足內存分配需求時,拋出OOM異常。
運行時常量池是方法區的一部分。用於存放編譯期生成的各類字面量和符號引用。
當常量池沒法再請到內存時會拋出OOM異常。
直接內存不是虛擬機運行時數據區的一部分,不是Java虛擬機規範中定義的內存區域。但這部份內存也被頻繁使用,也可能致使OOM。本機直接內存的分配不會受到Java堆大小的限制,但仍是會受到本機總內存大小以及處理器尋址空間的限制。