jvm中的堆棧與數據結構中的堆棧


堆棧這個概念存在於數據機構中,也存在於jvm虛擬機中,但是這兩個概念不是相同的。

在數據結構中,堆和棧是數據結構,堆是完全二叉樹,堆中個元素是有序的。在這個二叉樹中所喲的雙親節點和孩子及誒到哪存在着大小關系,如所有的雙親接納都大於孩子節點則為大頭對,如果所有的雙親節點都小於其孩子及誒到哪說明這是一個小頭堆,建堆的過程就是一個排序的過程,堆的查詢效率也很高。而棧是一種特殊的線性表,具有先進后出,只允許在一端(棧頂)插入、刪除的特點。

在jvm虛擬機中得堆棧對應內存的不同區域,和數據結構中所說的堆棧是兩碼事。

下面介紹jvm中得堆棧以及jvm內存分配:

JVM的體系結構如下:

如下圖所示,JVM的體系結構包含幾個主要的子系統和內存區:

類裝載子系統 ,負責把類從文件系統中裝入內存

GC子系統 ,垃圾收集器的主要工作室自動回收不再運行的程序引用對象所占用的內存,此外,它還可能負責那些還在使用的對象,以減少的堆碎片。

內存區 ,用於存儲字節碼,程序運行時創建的對象,傳遞給方法的參數,返回值,局部變量和中間計算結果。

執行引擎: 
1、最簡單的:一次性解釋字節碼。 
2、快,但消耗內存的:“即時編譯器”,第一次被執行的字節碼會被編譯成機器代碼,放入緩存,以后調用可以重用。 
3、自適應優化器,虛擬機開始的時候會解釋字節碼,但是會監視運行中程序的活動,並記錄下使用最頻繁的代碼段。程序運行的時候,虛擬機只把使用最頻繁的代碼編譯成本地代碼,其他的代碼由於使用的並不頻繁,繼續保留為字節碼--由虛擬機繼續解釋他們。一般可以使java虛擬機80%~90%的時間里執行被優化過的本地代碼,只需要編譯10%~20%對性能優影響的代碼。 
4、由硬件芯片組成,他用本地方法執行java字節碼,這種執行引擎實際上是內嵌在芯片里的。

2. Java的內存分配

在Java程序運行過程中,JVM定義了各種區域用於存儲運行時數據。其中的有些數據區域在JVM啟動時創建,並只在JVM退出時銷毀。其它的數據區域與每個線程相關。這些數據區域,在線程創建時創建,在線程退出時銷毀。

2.1 程序計數器寄存器(The pc Register)

JVM支持多個線程同時運行。每個JVM都有自己的程序計數器。在任何一個點,每個JVM線程執行單個方法的代碼,這個方法是線程的當前方法。如果方法不是native的,程序計數器寄存器包含了當前執行的JVM指令的地址,如果方法是 native的,程序計數器寄存器的值不會被定義。 JVM的程序計數器寄存器的寬度足夠保證可以持有一個返回地址或者native的指針。

2.2 棧

1)棧與線程

JVM是基於棧的虛擬機.JVM為每個新創建的線程都分配一個棧.也就是說,對於一個Java程序來說,它的運行就是通過對棧的操作來完成的。棧以幀為單位保存線程的狀態。JVM對棧只進行兩種操作:以幀為單位的壓棧和出棧操作。

我們知道,某個線程正在執行的方法稱為此線程的當前方法.我們可能不知道,當前方法使用的幀稱為當前幀。當線程激活一個Java方法,JVM就會在線程的 Java堆棧里新壓入一個幀。這個幀自然成為了當前幀.在此方法執行期間,這個幀將用來保存參數,局部變量,中間計算過程和其他數據.這個幀在這里和編譯原理中的活動紀錄的概念是差不多的.

從Java的這種分配機制來看,堆棧又可以這樣理解:棧(Stack)是操作系統在建立某個進程時或者線程(在支持多線程的操作系統中是線程)為這個線程建立的存儲區域,該區域具有先進后出的特性。

2)棧中的方法調用

嵌套方法的出棧和入棧示意圖: 

上圖中描述了嵌套方法時,stack的內存分配圖,由上面可以知道,當嵌套方法調用時,嵌套越深,stack的內存就越晚才能釋放,因此,在實際開發過程中,不推薦大家使用遞歸來進行方法的調用,遞歸很容易導致stack flow。

非嵌套方法的出棧入棧過程:

2.3 堆

每一個Java應用都唯一對應一個JVM實例,每一個實例唯一對應一個堆。應用程序在運行中所創建的所有類實例或數組都放在這個堆中,並由應用所有的線程共享.跟C/C++不同,Java中分配堆內存是自動初始化的。Java中所有對象的存儲空間都是在堆中分配的,但是這個對象的引用卻是在堆棧中分配,也就是說在建立一個對象時從兩個地方都分配內存,在堆中分配的內存實際建立這個對象,而在堆棧中分配的內存只是一個指向這個堆對象的指針(引用)而已。

2.4 堆和棧的區別

1. 棧(stack)與堆(heap)都是Java用來在Ram中存放數據的地方 。與C++不同,Java自動管理棧和堆,程序員不能直接地設置棧或堆。

2. 棧的優勢是,存取速度比堆要快 ,僅次於直接位於CPU中的寄存器。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。另外,棧數據可以共享,詳見第3點。堆的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會自動收走這些不再使用的數據。但缺點是,由於要在運行時動態分配內存,存取速度較慢。

3. 方法區

JVM有一個被所有的線程共享方法區。方法區類似於傳統語言的編譯后代碼的存儲區,或者UNIX進程中的text段。它存儲每個類結構例如常量池(constant pool),成員字段域和方法和構造函數,包含類和實例初始化和接口類型類型中用到的特殊方法的代碼。

方法區在虛擬機啟動時創建。盡管方法區在邏輯上時heap的一部分,簡單的實現仍然可以選擇對它既不回收也不壓縮。

The Java virtual machine has a method area that is shared among all Java virtual machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in a UNIX process. It stores per-class structures such as the runtime constant pool, field and method data, and the code for methods and constructors, including the special methods (§3.9) used in class and instance initialization and interface type initialization.

The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This version of the Java virtual machine specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous.

A Java virtual machine implementation may provide the programmer or the user control over the initial size of the method area, as well as, in the case of a varying-size method area, control over the maximum and minimum method area size.

 

 

Java中變量分為靜態變量,實例變量,臨時變量。那么各種變量具體保存在JVM中的何處呢?

1 靜態變量:位於方法區。

2 實例變量:作為對象的一部分,保存在堆中。

3 臨時變量:保存於棧中,棧隨線程的創建而被分配。

注:常量:位於常量池,而常量池位於方法區,若JVM采用的是分代垃圾回收,則方法區就是Perm區(永久存儲區)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM