原網頁:JavaGuide
JVM在執行Java程序過程中會把它管理的內存劃分成若干個不同的數據區域。JDK1.8和之前的版本略有不同,下面會介紹到。
JDK1.8之前:
JDK1.8之后:
這其中線程私有的:
- 虛擬機棧;
- 程序計數器;
- 本地方法棧;
線程共享的:
- 堆;
- 方法區;
- 直接內存(非運行時數據區的一部分)
程序計數器
程序計數器是一塊較小的內存空間,可以看作是當前線程所執行的字節碼的行號指示器。字節碼解釋器工作時通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等功能都需要依賴這個計數器完成。
Java虛擬機棧
與程序計數器一樣,Java虛擬機棧也是線程私有的,它的生命周期和線程相同,描述的是Java方法執行的內存模型,每次方法調用的數據都是通過棧傳遞的。
Java內存可以粗糙的分為堆內存和棧內存,其中棧就是現在說的虛擬機棧,或者說是虛擬機棧中局部變量表部分。(實際上,Java虛擬機棧是由一個個棧幀組成,每個棧幀中都擁有:局部變量表、操作數幀、動態鏈接、方法出口信息)。
局部變量表主要存放了編譯期可知的各種數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference類型,它不同于對象本身,可能是一個指向對象的起始位置的引用指針,也可能是指向一個代表對象的句柄或其他于此對象相關的位置)。
方法/函數如何調用?
Java??梢灶惐葦祿Y構中棧,Java棧中保存的主要內容是棧幀,每一次函數調用都會有一個對應的棧幀被壓入Java棧,每一個函數調用結束后,都會有一個棧幀被彈出。
Java方法有兩種返回方式:
1、return語句。
2、拋出異常。
不管哪種返回方式都會導致棧幀被彈出。
堆
Java虛擬機所管理內存中最大的一塊,Java堆是所有線程共享的一塊內存區域,在虛擬機啟動時創建。此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例以及數組都在這里分配內存。
Java世界中“幾乎”幾乎所有的對象都在堆中分配,但是隨著JTI編譯器的發展與逃逸分析技術逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙的變化,所有的對象都分配到對上也漸漸變得不那么“絕對”了。從JDK1.7開始已經默認開啟逃逸分析,如果某些方法中的對象引用沒有被返回或者未被外面使用(也就是未逃逸出去),那么對象可以直接在棧上分配內存。
Java堆是垃圾收集器管理的主要區域,因此也被稱作GC堆。從垃圾回收的角度,由于現在收集器基本都采用分代垃圾收集算法,所以Java堆還可以細分為:新生代和老年代;進一步細致一點還有:Eden空間、From Survivor、To Survivor空間等。進一步劃分的目的是更好地回收內存,或者更快地分配內存。
在JDK7版本以及JDK7版本之前,堆內存通常被分為以下三部分:
1、新生代內存
2、老生代
3、永生代
JDK8版本之后,方法區被移除了,取而代之的是元空間,元空間使用的是直接內存。
大部分情況,對象都會首先在 Eden 區域分配,在一次新生代垃圾回收后,如果對象還存活,則會進入 s0 或者 s1,并且對象的年齡還會加 1(Eden 區->Survivor 區后對象的初始年齡變為 1),當它的年齡增加到一定程度(默認為 15 歲),就會被晉升到老年代中。
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注服務器之家的更多內容!
原文鏈接:https://blog.csdn.net/weixin_51093884/article/details/121024628