根據(jù)編譯原理,程序在運(yùn)行時(shí)的內(nèi)存分配策略有三種:
1.靜態(tài) Static
指在編譯時(shí)就能確定的每個(gè)數(shù)據(jù)目標(biāo)在運(yùn)行時(shí)刻需要的存儲(chǔ)空間需求。因而在編譯的時(shí)候就可以給他們分配固定的存儲(chǔ)空間席镀。 這種數(shù)據(jù)目標(biāo)在編譯時(shí)就為他們分配固定的內(nèi)存。
限制:
- 代碼中不能有可變數(shù)據(jù)結(jié)構(gòu)夏漱,如數(shù)組豪诲。
- 代碼中不允許有遞歸或嵌套結(jié)構(gòu)的出現(xiàn)。
public class EaseConstant {
public static final String MESSAGE_ATTR_IS_VOICE_CALL = "is_voice_call";
public static final String MESSAGE_ATTR_IS_VIDEO_CALL = "is_video_call";
public static final String MESSAGE_ATTR_IS_BIG_EXPRESSION = "em_is_big_expression";
public static final String MESSAGE_ATTR_EXPRESSION_ID = "em_expression_id";
public static final String MESSAGE_ATTR_AT_MSG = "em_at_list";
public static final String MESSAGE_ATTR_VALUE_AT_MSG_ALL = "ALL";
public static final int CHATTYPE_SINGLE = 1;
public static final int CHATTYPE_GROUP = 2;
public static final int CHATTYPE_CHATROOM = 3;
public static final String EXTRA_CHAT_TYPE = "chatType";
public static final String EXTRA_USER_ID = "userId";
}
2.棧式 Stack
棧式存儲(chǔ)分配可稱為動(dòng)態(tài)存儲(chǔ)分配挂绰,是由一個(gè)類似于堆棧的運(yùn)行棧來(lái)實(shí)現(xiàn)的屎篱,和靜態(tài)存儲(chǔ)分配相反,在棧式存儲(chǔ)方案中扮授,程序?qū)?shù)據(jù)區(qū)的需求在編譯時(shí)是完全未知的芳室,只有到運(yùn)行的時(shí)候才能知道。
指在編譯時(shí)不能確定大小刹勃,但在運(yùn)行的時(shí)候能夠確定,且規(guī)定在運(yùn)行中進(jìn)入一個(gè)程序模塊時(shí)嚎尤,就必須知道該模塊所需要的數(shù)據(jù)區(qū)大小荔仁,才能為其分配內(nèi)存,和我們?cè)跀?shù)據(jù)結(jié)構(gòu)中所知道的棧一樣,內(nèi)存分配為e棧原則乏梁,先進(jìn)后出的原則進(jìn)行分配次洼。
分配是在運(yùn)行時(shí)執(zhí)行的,但是大小是在編譯時(shí)確定的遇骑;
特點(diǎn):
在C/C++中卖毁,所有的方法調(diào)用都是通過(guò)棧來(lái)進(jìn)行的,所有局部變量落萎,形式參數(shù)都是從棧中分配內(nèi)存空間的亥啦。
棧的分配和回收:
棧分配內(nèi)存空間:從棧低向棧頂,依次存儲(chǔ)练链;
椣柰眩回收內(nèi)存空間:修改棧頂指針的位置,完成棧中內(nèi)容銷毀媒鼓,這樣的模式速度很快届吁。
棧 :存放基本數(shù)據(jù)類型,速度快
- 棧中主要存放一些基本類型的變量(int, short, long, byte, float, double, boolean, char)和對(duì)象句柄绿鸣;
- 棧的存取速度比堆要快疚沐;
- 棧數(shù)據(jù)可以共享;
- 棧的數(shù)據(jù)大小與生存期必須是確定的潮模,缺乏靈活性濒旦。
3.堆式 Heap
指編譯時(shí),運(yùn)行時(shí)模塊入口都不能確定存儲(chǔ)要求的數(shù)據(jù)結(jié)構(gòu)的內(nèi)存分配再登。
比如可變長(zhǎng)度的串和對(duì)象實(shí)例尔邓。
堆由大片的可利用的塊或空閑組成,堆中的內(nèi)存可以按照任意順序分配和釋放锉矢。
堆是在運(yùn)行的時(shí)候梯嗽,請(qǐng)求操作系統(tǒng)分配給自己內(nèi)存,由于從操作系統(tǒng)管理的內(nèi)存分配沽损,所以在分配和銷毀的時(shí)候都要占用時(shí)間灯节,因此對(duì)的效率低下。
堆的優(yōu)點(diǎn):編譯時(shí)不必知道要從堆里分配多少存儲(chǔ)空間绵估,也不必知道存儲(chǔ)的數(shù)據(jù)要在堆里停留多長(zhǎng)時(shí)間鳞滨,因此堆存儲(chǔ)數(shù)據(jù)時(shí),靈活性比較大粘姜;
在面向?qū)ο缶幊讨械廖拢咽潜夭豢缮俚模驗(yàn)槊嫦驅(qū)ο蟮亩鄳B(tài)性缝左,多態(tài)變量所需的存儲(chǔ)空間只有在運(yùn)行時(shí)創(chuàng)建了對(duì)象之后才能確定亿遂。
堆: 用new建立浓若,垃圾自動(dòng)回收負(fù)責(zé)回收
- 堆是一個(gè)"運(yùn)行時(shí)"數(shù)據(jù)區(qū),類實(shí)例化的對(duì)象就是從堆上去分配空間的蛇数;
- 在堆上分配空間是通過(guò)"new"等指令建立的挪钓;
- Java針對(duì)堆的操作和C++的區(qū)別就是,Java不需要在空間不用的時(shí)候來(lái)顯式的釋放耳舅;
- Java的堆是由Java的垃圾回收機(jī)制來(lái)負(fù)責(zé)處理的碌上,堆是動(dòng)態(tài)分配內(nèi)存大小,垃圾收集器可以自動(dòng)回收不再使用的內(nèi)存空間浦徊。
- 但缺點(diǎn)是馏予,因?yàn)樵谶\(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,所以內(nèi)存的存取速度較慢辑畦。
4. 堆和棧的比較
比較方面 | 堆 | 棧 |
---|---|---|
功能的比較 | 存放對(duì)象 | 執(zhí)行程序 |
存儲(chǔ)內(nèi)容 | new關(guān)鍵字創(chuàng)建的內(nèi)容 | 局部變量吗蚌,形式參數(shù) |
存儲(chǔ)速度 | 慢 | 快(所以用來(lái)執(zhí)行程序) |
5.JVM中的堆棧
JVM是基于堆棧的虛擬機(jī),JVM中的堆棧是兩塊不同的存儲(chǔ)區(qū)域纯出。
JVM為每個(gè)線程程都分配了一個(gè)堆和棧蚯妇,所以對(duì)于java程序來(lái)說(shuō),程序的運(yùn)行是通過(guò)對(duì)堆棧的操作來(lái)完成的暂筝。
JVM 堆 | JVM 棧 |
---|---|
是存儲(chǔ)的單位 | 是運(yùn)行時(shí)的單位 |
JVM堆解決的是數(shù)據(jù)存儲(chǔ)的問(wèn)題箩言,即數(shù)據(jù)怎么放、放在哪兒焕襟。 | JVM棧解決程序的運(yùn)行問(wèn)題陨收,即程序如何執(zhí)行,或者說(shuō)如何處理數(shù)據(jù); |
JVM堆中存的是對(duì)象鸵赖。 | JVM棧中存的是基本數(shù)據(jù)類型和JVM堆中對(duì)象的引用 |
一個(gè)對(duì)象的大小是不可估計(jì)的务漩,或者說(shuō)是可以動(dòng)態(tài)變化的,但是在JVM棧中它褪,一個(gè)對(duì)象只對(duì)應(yīng)了一個(gè)4btye的引用(JVM堆JVM棧分離的好處:))饵骨。
為什么不把基本類型放JVM堆中呢?
因?yàn)榛绢愋推湔加玫目臻g一般是1~8個(gè)字節(jié)(需要空間比較少),而且因?yàn)槭腔绢愋兔4颍圆粫?huì)出現(xiàn)動(dòng)態(tài)增長(zhǎng)的情況(長(zhǎng)度固定)居触,因此JVM棧中存儲(chǔ)就夠了,如果把他存在JVM堆中是沒有什么意義的(還會(huì)浪費(fèi)空間老赤,后面說(shuō)明)轮洋。可以這么說(shuō)抬旺,基本類型和對(duì)象的引用都是存放在JVM棧中弊予,而且都是幾個(gè)字節(jié)的一個(gè)數(shù),因此在程序運(yùn)行時(shí)嚷狞,他們的處理方式是統(tǒng)一的块促。
但是基本類型荣堰、對(duì)象引用和對(duì)象本身就有所區(qū)別了床未,因?yàn)橐粋€(gè)是JVM棧中的數(shù)據(jù)一個(gè)是JVM堆中的數(shù)據(jù)的引用竭翠。最常見的一個(gè)問(wèn)題就是,Java中參數(shù)傳遞時(shí)的問(wèn)題薇搁。
JAVA中堆棧的應(yīng)用
Java中的參數(shù)傳遞時(shí)傳值呢?還是傳引用?
要說(shuō)明這個(gè)問(wèn)題斋扰,先要明確兩點(diǎn):
1.不要試圖與C進(jìn)行類比,Java中沒有指針的概念
2.程序運(yùn)行永遠(yuǎn)都是在JVM棧中進(jìn)行的啃洋,因而參數(shù)傳遞時(shí)传货,只存在傳遞基本類型和對(duì)象引用的問(wèn)題,不會(huì)直接傳對(duì)象本身宏娄。總結(jié):傳遞的是對(duì)象的引用值或是基本類型的值问裕;
明確以上兩點(diǎn)后。Java在方法調(diào)用傳遞參數(shù)時(shí)孵坚,因?yàn)闆]有指針粮宛,所以它都是進(jìn)行傳值調(diào)用(這點(diǎn)可以參考C的傳值調(diào)用)。因此卖宠,很多書里面都說(shuō)Java是進(jìn)行傳值調(diào)用巍杈,這點(diǎn)沒有問(wèn)題,而且也簡(jiǎn)化的C中復(fù)雜性扛伍。
但是傳引用的錯(cuò)覺是如何造成的呢?
在運(yùn)行JVM棧中筷畦,基本類型和引用的處理是一樣的,都是傳值刺洒,所以鳖宾,如果是傳引用的方法調(diào)用,也同時(shí)可以理解為“傳引用值”的傳值調(diào)用逆航,即引用的處理跟基本類型是完全一樣的鼎文。但是當(dāng)進(jìn)入被調(diào)用方法時(shí),被傳遞的這個(gè)引用的值纸泡,被程序解釋(或者查找)到JVM堆中的對(duì)象漂问,這個(gè)時(shí)候才對(duì)應(yīng)到真正的對(duì)象。如果此時(shí)進(jìn)行修改女揭,修改的是引用對(duì)應(yīng)的對(duì)象蚤假,而不是引用本身,即:修改的是JVM堆中的數(shù)據(jù)吧兔。所以這個(gè)修改是可以保持的了磷仰。
對(duì)象,從某種意義上說(shuō)境蔼,是由基本類型組成的灶平∷磐ǎ可以把一個(gè)對(duì)象看作為一棵樹,對(duì)象的屬性如果還是對(duì)象逢享,則還是一顆樹(即非葉子節(jié)點(diǎn))罐监,基本類型則為樹的葉子節(jié)點(diǎn)。程序參數(shù)傳遞時(shí)瞒爬,被傳遞的值本身都是不能進(jìn)行修改的弓柱,但是,如果這個(gè)值是一個(gè)非葉子節(jié)點(diǎn)(即一個(gè)對(duì)象引用)侧但,則可以修改這個(gè)節(jié)點(diǎn)下面的所有內(nèi)容矢空。
JVM堆和JVM棧中,JVM棧是程序運(yùn)行最根本的東西禀横。程序運(yùn)行可以沒有JVM堆屁药,但是不能沒有JVM棧。而JVM堆是為JVM棧進(jìn)行數(shù)據(jù)存儲(chǔ)服務(wù)柏锄,說(shuō)白了JVM堆就是一塊共享的內(nèi)存酿箭。不過(guò),正是因?yàn)镴VM堆和JVM棧的分離的思想绢彤,才使得Java的垃圾回收成為可能七问。
JVM中線程堆棧
線程(thread),有時(shí)被稱為輕量級(jí)進(jìn)程(Lightweight Process,LWP)茫舶,是程序執(zhí)行流的最小單元械巡。一個(gè)標(biāo)準(zhǔn)的線程由線程ID,當(dāng)前指令指針(PC)饶氏,寄存器集合和堆棧組成讥耗。另外,線程是進(jìn)程中的一個(gè)實(shí)體疹启,是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位古程,線程自己不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源喊崖,但它可與同屬一個(gè)進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源挣磨。一個(gè)線程可以創(chuàng)建和撤消另一個(gè)線程,同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行荤懂。由于線程之間的相互制約茁裙,致使線程在運(yùn)行中呈現(xiàn)出間斷性。線程也有就緒节仿、阻塞和運(yùn)行三種基本狀態(tài)晤锥。 線程是程序中一個(gè)單一的順序控制流程.在單個(gè)程序中同時(shí)運(yùn)行多個(gè)線程完成不同的工作,稱為多線程。
1矾瘾、線程與進(jìn)程
線程和進(jìn)程的區(qū)別在于,子進(jìn)程和父進(jìn)程有不同的代碼和數(shù)據(jù)空間,而多個(gè)線程則共享數(shù)據(jù)空間,每個(gè)線程有自己的執(zhí)行堆棧和程序計(jì)數(shù)器為其執(zhí)行上下文.多線程主要是為了節(jié)約CPU時(shí)間,發(fā)揮利用,根據(jù)具體情況而定. 線程的運(yùn)行中需要使用計(jì)算機(jī)的內(nèi)存資源和CPU
通常在一個(gè)進(jìn)程中可以包含若干個(gè)線程女轿,它們可以利用進(jìn)程所擁有的資源。在引入線程的操作系統(tǒng)中壕翩,通常都是把進(jìn)程作為分配資源的基本單位蛉迹,而把線程作為獨(dú)立運(yùn)行和獨(dú)立調(diào)度的基本單位。由于線程比進(jìn)程更小戈泼,基本上不擁有系統(tǒng)資源婿禽,故對(duì)它的調(diào)度所付出的開銷就會(huì)小得多赏僧,能更高效的提高系統(tǒng)內(nèi)多個(gè)程序間并發(fā)執(zhí)行的程度大猛。