java 堆棧內存分析詳解

     計算機術語裏面堆和棧表明不一樣的存儲結構:stack-棧;heap-堆java

     因此java虛擬機(JVM)中堆和棧是兩種內存數組

堆、棧對比
對比點
JVM中的功能 內存數據區 內存指令區
動靜態 運行時數據區,動態地分配內存大小  
存儲數據 對象實例(保存對象實例,其實是保存對象實例的屬性值,屬性的類型和對象自己的類型標記等,並不保存對象的方法(方法是指令,保存在stack中)。對象實例在heap中分配好之後,須要在stack中保存一個4字節的heap內存地址,用來定位該對象實例在heap中的位置,便於找到該對象實例) 基本數據類型, 指令代碼,常量,對象的引用地址(基本數據類型包括byte、int、char、long、float、double、boolean和short,函數方法屬於指令)
回收方式 由垃圾回收來負責 超過變量的做用域後,自動釋放
優缺點 優點是能夠動態地分配內存大小,生存期也沒必要事先告訴編譯器,由於它是在運行時動態分配內存的,Java的垃圾收集器會自動收走這些再也不使用的數據。但缺點是,因爲要在運行時動態分配內存,存取速度較慢。 棧的優點是,存取速度比堆要快,僅次於寄存器,棧數據能夠共享。但缺點是,存在棧中的數據大小與生存期必須是肯定的,缺少靈活性。

 

棧:至關於內存指令區  ,存儲着基本數據類型, 指令代碼,常量,對象的引用地址(基本數據類型包括byte、int、char、long、float、double、boolean和short,函數方法屬於指令)。函數

堆:是一個運行時數據區,內存數據區, 存儲着對象實例,保存對象實例,其實是保存對象實例的屬性值,屬性的類型和對象自己的類型標記等,並不保存對象的方法(方法是指令,保存在stack中)。對象實例在heap中分配好之後,須要在stack中保存一個4字節的heap內存地址,用來定位該對象實例在heap中的位置,便於找到該對象實例。spa

 

網上流傳的一些堆棧的描述:線程

在函數中定義的一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配。當在一段代碼塊中定義一個變量時,java就在棧中爲這個變量分配內存空間,當超過變量的做用域後,java會自動釋放掉爲該變量分配的內存空間,該內存空間能夠馬上被另做他用。指針

堆內存用於存放由new建立的對象和數組。在堆中分配的內存,由java虛擬機自動垃圾回收器來管理。在堆中產生了一個數組或者對象後,還能夠在棧中定義一個特殊的變量,這個變量的取值等於數組或者對象在堆內存中的首地址,在棧中的這個特殊的變量就變成了數組或者對象的引用變量,之後就能夠在程序中使用棧內存中的引用變量來訪問堆中的數組或者對象,引用變量至關於爲數組或者對象起的一個別名,或者代號。code

引用變量是普通變量,定義時在棧中分配內存,引用變量在程序運行到做用域外釋放。而數組&對象自己在堆中分配,即便程序運行到使用new產生數組和對象的語句所在地代碼塊以外,數組和對象自己佔用的堆內存也不會被釋放,數組和對象在沒有引用變量指向它的時候,才變成垃圾,不能再被使用,可是仍然佔着內存,在隨後的一個不肯定的時間被垃圾回收器釋放掉。這個也是java比較佔內存的主要緣由,實際上,棧中的變量指向堆內存中的變量,這就是 Java 中的指針!對象

 

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

每個Java應用都惟一對應一個JVM實例,每個實例惟一對應一個堆。應用程序在運行中所建立的全部類實例或數組都放在這個堆中,並由應用全部的線程共享.內存

 

Java的堆是一個運行時數據區,類的(對象從中分配空間。這些對象經過new、newarray、anewarray和multianewarray等指令創建,它們不須要程序代碼來顯式的釋放。堆是由垃圾回收來負責的,堆的優點是能夠動態地分配內存大小,生存期也沒必要事先告訴編譯器,由於它是在運行時動態分配內存的,Java的垃圾收集器會自動收走這些再也不使用的數據。但缺點是,因爲要在運行時動態分配內存,存取速度較慢。 

  棧的優點是,存取速度比堆要快,僅次於寄存器,棧數據能夠共享。但缺點是,存在棧中的數據大小與生存期必須是肯定的,缺少靈活性。棧中主要存放一些基本類型的變量(,int, short, long, byte, float, double, boolean, char)和對象句柄。 

棧有一個很重要的特殊性,就是存在棧中的數據能夠共享。假設咱們同時定義: 

  int a = 3; 

  int b = 3; 

  編譯器先處理int a = 3;首先它會在棧中建立一個變量爲a的引用,而後查找棧中是否有3這個值,若是沒找到,就將3存放進來,而後將a指向3。接着處理int b = 3;在建立完b的引用變量後,由於在棧中已經有3這個值,便將b直接指向3。這樣,就出現了a與b同時均指向3的狀況。這時,若是再令a=4;那麼編譯器會從新搜索棧中是否有4值,若是沒有,則將4存放進來,並令a指向4;若是已經有了,則直接將a指向這個地址。所以a值的改變不會影響到b的值。要注意這種數據的共享與兩個對象的引用同時指向一個對象的這種共享是不一樣的,由於這種狀況a的修改並不會影響到b, 它是由編譯器完成的,它有利於節省空間。而一個對象引用變量修改了這個對象的內部狀態,會影響到另外一個對象引用變量

相關文章
相關標籤/搜索