Java内存之栈与堆
?昨天中午,發(fā)了一篇equals和==區(qū)別的博文,晚上再看時有幾位大牛指出了其中的一些錯誤,很感謝他們的留言,一句簡簡單單的留言給了我對這些錯誤知識點改正的機會。或許這就是從事互聯(lián)網行業(yè)所提倡的互幫互助的精神吧,因為有分享,有交流,互聯(lián)網才會發(fā)展的如此迅猛。大牛提的一個觀點很好,好的東西可以拿出來分享,錯的東西卻可能帶給別人錯誤的理解,這一點我確實得向看了我寫了一些bug博客的人道個歉。
針對大牛所指出的錯誤,晚上翻出了資料,重新溫習了一遍。繼續(xù)總結一下:
一、在JVM中,內存是如何被劃分的?
java把內存分兩種:一種是棧內存,另一種是堆內存
1. 在函數(shù)中定義的基本類型變量和對象的引用變量都在函數(shù)的棧內存中分配;(所以int的東西放在棧中)
2. 堆內存用來存放由new創(chuàng)建的對象和數(shù)組以及對象的實例變量。
在函數(shù)(代碼塊)中聲明(這里并沒有實例化)一個變量時,java就在棧中為這個變量分配內存空間,當超過變量的作用域后,java會自動釋放掉為該變量所分配的內存空間;在堆中分配的內存由java虛擬機的自動垃圾回收器來管理
二、堆和棧的優(yōu)缺點比較
1. 堆的優(yōu)勢是可以動態(tài)分配內存大小,生存期也不必事先告訴編譯器,因為它是在運行時動態(tài)分配內存的;缺點就是要在運行時動態(tài)分配內存,存取速度較慢。
2. 棧的優(yōu)勢是,存取速度比堆要快,僅次于直接位于CPU中的寄存器,棧數(shù)據(jù)可以共享;但缺點是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。
三、new出來的對象存在內存的什么地方?
在Java中,創(chuàng)建一個對象包括對象的聲明和對象的實例化兩部分。程序員需要通過關鍵字new為每個對象申請內存空間(基本類型除外),所有的對象都在堆(heap)中分配空間。
舉例說明的一段代碼上面的這段代碼,當我們使用NewTest test = new NewTest()時,我們做如下分析:
NewTest test : 聲明一個對象test時,將在棧內存為對象的引用變量test分配內存空間,但NewTest的值為空,稱test是一個空對象。空對象不能使用,因為它還沒有引用任何"實體"。
test = new NewTest()時,在堆內存中為類的成員變量aaa,bbb分配內存,并將其初始化為各數(shù)據(jù)類型的默認值;接著進行顯式初始化(類定義時的初始化值);最后調用構造方法,為成員變量賦值,返回堆內存中對象的引用(相當于首地址)給引用變量test,以后就可以通過test來引用堆內存中的對象了。
?
創(chuàng)建兩個不同對象代碼在使用同一個類創(chuàng)建兩個不同的對象的時候,這些對象實例將在堆中被分配到不同的內存空間,改變其中一個對象的狀態(tài)不會影響其他對象的狀態(tài)。
四、Java基本類型在內存中的存儲
這里重點討論一下八種基本類型(int, short, long, byte, float, double, boolean, char)在內存中時如何存放的。我們所指的八種基本類型定義的變量,是指形式如 int a=3、char aa ='a'類型的,即不通過new的。這里的aa時指向char類型的一個引用,指向'a'這個字面值。這些字面值的數(shù)據(jù),由于大小可知,生存期可知(這些字面值定義在某個程序塊里面,程序塊退出后,字段值就消失了),出于追求速度的原因,就存在于棧中。
另外,棧有一個很重要的特殊性,就是存在棧中的數(shù)據(jù)可以共享。
比如:我們同時定義:
long a =3;
long b =3;
編譯器處理的過程是:
1. 編譯器先處理long a = 3;首先它會在棧中創(chuàng)建一個變量為a的引用,然后查找有沒有字面值為3的地址,沒找到,就開辟一個存放3這個字面值的地址,然后將a指向3的地址。
2. 接著處理long b = 3;在創(chuàng)建完b這個引用變量后,由于在棧中已經有3這個字面值,便將b直接指向3的地址。這樣,就出現(xiàn)了a與b同時均指向3的情況。
定義完a與b的值后,如果再令a = 4,這時,b不會等于4,還是等于3。在編譯器內部,遇到時,它就會重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。
五、基本類型對應的包裝類
基本類型都有對應的包裝類:如int對應Integer類,double對應Double類等,基本類型的定義都是直接在棧中,如果用包裝類來創(chuàng)建對象,就和普通對象一樣了。例如:
int a=0;a直接存儲在棧中。
Integer b= new Integer(5);b對象數(shù)據(jù)(這里指的是5)存儲在堆中,b的引用存儲在棧中,通過棧中的引用來操作對象。
六、String在內存中的存放
String是一個特殊的包裝類數(shù)據(jù),可以用用以下兩種方式創(chuàng)建:
String str = new String("abc");第一種創(chuàng)建方式,和普通對象的的創(chuàng)建過程一樣;
String str = "abc"; 第二種創(chuàng)建方式,類似于基本數(shù)據(jù)類型的創(chuàng)建,變量名和數(shù)據(jù)存放在棧空間中。
七、數(shù)組在內存中的存放
int x[] 或者int []x 時,在內存棧空間中創(chuàng)建一個數(shù)組引用,通過該數(shù)組名來引用數(shù)組。
x = new int[5] 將在堆內存中分配5個保存int型數(shù)據(jù)的空間,堆內存的首地址放到棧內存中,每個數(shù)組元素被初始化為0.
八、static變量在內存中的存放
用static的修飾的變量和方法,實際上是指定了這些變量和方法在內存中的"固定位置"-static storage,可以理解為所有實例對象共有的內存空間。static變量有點類似于C中的全局變量的概念;靜態(tài)表示的是內存的共享,就是它的每一個實例都指向同一個內存地址。把static拿來,就是告訴JVM它是靜態(tài)的,它的引用(含間接引用)都是指向同一個位置,在那個地方,你把它改了,它就不會變成原樣,你把它清理了,它就不會回來了。
那靜態(tài)變量與方法是在什么時候初始化的呢?
對于兩種不同的類屬性,static屬性與instance屬性,初始化的時機是不同的。instance屬性在創(chuàng)建實例的時候初始化,static屬性在類加載,也就是第一次用到這個類的時候初始化,對于后來的實例的創(chuàng)建,不再進行初始化。
轉載于:https://blog.51cto.com/shuaigee/1131734
總結
以上是生活随笔為你收集整理的Java内存之栈与堆的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AIX 6.1 异步 I/O 的 配置与
- 下一篇: Notice: Undefined va