概述
先Copy一個(gè)概念:JVM是基于堆棧的虛擬機(jī)结洼。JVM為每個(gè)新創(chuàng)建的線程都分配一個(gè)堆棧.也就是說(shuō),對(duì)于一個(gè)Java程序來(lái)說(shuō)塘秦,它的運(yùn)行就是通過(guò)對(duì)堆棧的操作來(lái)完成的。堆棧以幀為單位保存線程的狀態(tài)躺翻。JVM對(duì)堆棧只進(jìn)行兩種操作:以幀為單位的壓棧和出棧操作。
例子分析
堆是用來(lái)存儲(chǔ)new出來(lái)的對(duì)象,也就是真實(shí)對(duì)象的存儲(chǔ)地方。棧是用來(lái)存儲(chǔ)基本變量屏鳍、局部變量及對(duì)象的引用的。
舉個(gè)來(lái)說(shuō)明吧
class User {
private int id;
private String name;
public User(int sid, String sname) {
this.id = sid;
this.name = sname;
}
}
public void test() {
int a = 10;
int b = 10;
b = 12;
String c = "hello";
String d = new String("hello");
User user = new User(10, "hello");
}
基本變量類(lèi)型都是存儲(chǔ)在棧中的局服,所以int型的a、b驳遵、c都存在棧中淫奔。具體的操作再來(lái)分析下:
int a = 10會(huì)檢查棧中有沒(méi)有10這個(gè)值,沒(méi)有就創(chuàng)建了一個(gè)10的值堤结,再創(chuàng)建了a去指向10唆迁。
int b = 10同樣會(huì)檢查棧中有沒(méi)有10這個(gè)值,發(fā)現(xiàn)已經(jīng)存在竞穷,則創(chuàng)建b指向已存在的10唐责。在棧中,變量值是可以共享的瘾带。
b = 12檢查棧中有沒(méi)有12這個(gè)值鼠哥,沒(méi)有就創(chuàng)建一個(gè)12的值,再把b的指向12,這樣也不會(huì)影響a的值朴恳。
說(shuō)到String時(shí)抄罕,先說(shuō)說(shuō)JVM有一個(gè)常量存儲(chǔ)區(qū)域,是用來(lái)存常量的于颖,像代碼定義直接雙引號(hào)中的內(nèi)容就是存在常量存儲(chǔ)區(qū)域的呆贿。String不是基本變量類(lèi)型。
String c = "hello"會(huì)先到常量存儲(chǔ)區(qū)域找hello森渐,如果沒(méi)有做入,就在常量存儲(chǔ)區(qū)域創(chuàng)建hello值,棧中創(chuàng)建一個(gè)c指向常量區(qū)域的hello同衣。
String d = new String("hello")是new一String對(duì)象竟块,會(huì)先到常量區(qū)域檢查有沒(méi)hello值,如果有乳怎,就在堆中生成hello的一個(gè)對(duì)象副本彩郊,如果沒(méi)有就會(huì)在常量區(qū)先創(chuàng)建hello,再在堆中生成一個(gè)副本蚪缀。在棧中生成d秫逝,指向堆中的hello對(duì)象,d是對(duì)象的引用询枚。
User user = new User(10, "hello")违帆,會(huì)構(gòu)造函數(shù),構(gòu)造函數(shù)里的sid,sname是局部變量金蜀,會(huì)存儲(chǔ)在棧中刷后,指向的值是棧中的10和常量存儲(chǔ)中的hello。在堆中會(huì)有new User這個(gè)對(duì)象渊抄,在棧中會(huì)有user這個(gè)對(duì)象的引用尝胆。這里要說(shuō)一下,sid,sname是構(gòu)造方法執(zhí)行完后护桦,會(huì)自動(dòng)從棧中移除含衔,而成員變量id,name是對(duì)象的屬性,會(huì)在堆中存在二庵,需要等JAVA自動(dòng)回收機(jī)制進(jìn)行回收贪染。
當(dāng)執(zhí)行完test方法后,棧中的基礎(chǔ)變量和值及對(duì)象引用都會(huì)被自動(dòng)移除催享,釋放內(nèi)存杭隙。
通過(guò)例子應(yīng)該可以比較好理解哪些數(shù)據(jù)存在堆中,哪些數(shù)據(jù)存在棧中了因妙。
總結(jié)
堆分配內(nèi)存時(shí)痰憎,大小和生存期都是不確定的票髓,要生成的時(shí)候才知道,遵循先進(jìn)先出的原則信殊,讀取速度比較慢炬称。數(shù)據(jù)不能共享,每new一次都是一個(gè)新的對(duì)象涡拘。要由JAVA的垃圾回收機(jī)制來(lái)回收玲躯,所以容易造成內(nèi)存多高。
棧分配內(nèi)存時(shí)數(shù)據(jù)的大小和生存期是確定的鳄乏,在編譯時(shí)就知道了跷车,遵循先進(jìn)后出的原則,讀取速度快橱野,接近寄存器了朽缴。數(shù)據(jù)可以共享,節(jié)省內(nèi)存水援,也比較快密强。在生存期結(jié)束后會(huì)自動(dòng)釋放,效率更高蜗元。