普通進程棧區,在JVM通常僅僅用作線程棧,以下圖所示java
首先是永久代。永久代本質上是Java程序的代碼區和數據區。Java程序中類(class),會被加載到整個區域的不一樣數據結構中去,包括常量池、域、方法數據、方法體、構造函數、以及類中的專用方法、實例初始化、接口初始化等。這個區域對於操做系統來講,是堆的一個部分;而對於Java程序來講,這是容納程序自己及靜態資源的空間,使得JVM可以解釋執行Java程序。算法
其次是新生代和老年代。新生代和老年代纔是Java程序真正使用的堆空間,主要用於內存對象的存儲;數組
那麼這些區域如何對應JVM的內存模型呢,首先看一張經典的JVM內存模型圖:服務器
線程棧:在JVM中用作線程棧,每一個線程都會在這個區域開闢私有棧數據結構
程序計數器是一塊較小的內存空間,它能夠看作是當前線程所執行的字節碼的行號指示器,字節碼解釋器經過改變這個計數器的值來選取下一條須要執行的字節碼指令,分支循環,跳轉,異常處理,線程恢復等基礎功能,特別注意的是,若是線程正在執行的是一個java方法那這個計數器記錄的是字節碼指令的地址(位置),若是是執行的是Native方法,這個計數器爲空jvm
程序計數器該部份內存是惟一不會發生OutOfMemoryError異常的區域函數
java虛擬機棧,也在這個線程棧中,線程私有,每一個方法執行的同時都會建立一個棧幀,用於存儲局部變量表,操做數棧,動態連接,方法出口等信息.性能
局部變量表,存放了編譯期可知的各類基本數據類型(boolean,byte,char short,int float,long,double),對象引用(reference,指向對象的指針,或者表明對象的句柄)和returnAddress類型操作系統
在jvm規範中,對這個區域規定了兩種異常情況:1.若是線程請求的的棧深度大於虛擬機所容許的深度,將拋出StackOverFlowError異常,若是虛擬機棧能夠動態擴展,擴展時沒法申請到足夠的內存將拋出OutOfMemoryError異常線程
本地方法棧,與虛擬機棧的做用很是類似,只不過是服務於Native方法,也會拋出兩種異常
inux的普通進程所使用的堆區,在jvm(Hotspot)進程中分爲永久新生老年代三塊區域
永久代,對應於 jvm的方法區,
方法區:用於存儲已經被虛擬機加載的類信息,常量,靜態變量,即時編譯器編譯後的代碼,等數據.要特別注意的是.方法區和永久代並非等價的,這要取決於虛擬機的類型,牢牢是由於HotSpot使用永久代來實現方法區.對於其餘虛擬機並不存在永久代的概念,
運行時常量池是方法區的一部分,所以它也在永久代,用於存儲編譯期間生成的各類字面量和符號引用,什麼叫字面量呢,就是int i =1;這個1就是字面量,String str= "abc";這個abc是字面量,什麼叫符號引用呢,就是在一個類中Student stu = new Student("張三",28) new出來的Student對象在編譯後未加載前顯然不知道其實際內存地址,所以在class文件中用一串無異議的符號來代替對象的內存首地址,等class文件通過一系列的加載檢驗以後分配完內存,會將符號引用替換成直接引用
新生代和老年代
Java堆:新生代和老年代纔是對應於JVm內存模型中的java堆,它是被全部線程共享的一個內存區域,在虛擬機啓動時建立.它的惟一目的就是存放對象實例,幾乎全部的對象實例都在這裏分配內存,包括數組
java堆是垃圾收集器管理的主要區域,所以,不少時候也被稱爲GC堆,因爲如今收集器基本都採用分代收集算法,因此Java堆細分爲新生代和老年代;再細緻一點的有Eden空間,FROM Survivor空間,To Survivor空間等.
從內存分配的角度來看,線程共享的java堆中可能劃分出多個線程私有的分配緩衝區(Thread Local Allocation Buffer TLAB),進一步劃分是爲了更好的回收內存,或者更快的分配內存.
根據JVM規範,java堆能夠處於物理上不連續的內存空間中,只要邏輯上是連續的就能夠,若是在堆中內有內存完成實例分配,而且對沒法擴展出足夠的內存,將會拋出OutOfMemoryError異常
JVM中的直接內存,並非虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域,可是這部份內存也被頻繁地使用,並且也可能致使OutOfMemoryError,
在jdk1.4中新加入了NIO類,引入了一種基於通道(Channel)與緩衝區(BUffer)的IO方式,它可使用Native函數庫直接分配內存,而後經過一個存儲在java堆中的DirectByteBuffer對象做爲這塊內存引用進行操做,這樣能在一些場景中顯著提升性能,由於避免了Java堆和Native堆中來回複製數據.以下圖:NIO使用的堆外內存
顯然,本機直接內存的分配不會受到Java堆大小的限制,可是,既然是內存,確定仍是會受到本機總存的(包括RAM以及swap區域或者分頁文件),大小以及處理器尋址空間的限制.服務器管理員在配置虛擬機參數時,會根據實際內存設置-Xmx等參數信息.但常常忽略直接內存,使得各個內存區域總和大於物理內存限制(包括物理的和操做系統級的限制),從而致使動態擴展時出現OutOfMemoryError異常
https://mp.weixin.qq.com/s?__biz=MzI4NTEzMjc5Mw==&mid=2650554703&idx=1&sn=4b2ce0d3fa9017adb2dac9843f097882&chksm=f3f833d9c48fbacf242749ec8f40197d9ea5463dc46f47afc62fd93b3fe4f433a723ceddd515#rd