Java內(nèi)存劃分和堆棧的簡單整理

一直不理解堆棧的概念蕾额,很多視頻課程講解又不全面但荤,學(xué)習(xí)代碼的數(shù)據(jù)結(jié)構(gòu)和算法成為了我最多困惑的地方罗岖。最近閑暇,查了下資料腹躁,基于Java語言整理下內(nèi)存區(qū)域劃分的基礎(chǔ)知識(shí)桑包。
由于Java程序是交由JVM執(zhí)行的,所以在談Java內(nèi)存區(qū)域劃分的時(shí)候事實(shí)上是指JVM內(nèi)存區(qū)域劃分纺非。在討論JVM內(nèi)存區(qū)域劃分之前哑了,先來看一下Java程序具體執(zhí)行的過程:


Java程序執(zhí)行過程

運(yùn)行時(shí)數(shù)據(jù)區(qū)模塊

了解jvm的結(jié)構(gòu)之前,有必要先來了解一下操作系統(tǒng)的內(nèi)存基本結(jié)構(gòu)


操作系統(tǒng)存儲(chǔ)體系

以上是操作系統(tǒng)存儲(chǔ)層次【CPU <--- > 寄存器<--- > 緩存(最多三級(jí)緩存)<--- >內(nèi)存<--- >磁盤緩存<--- >固定磁盤存儲(chǔ)<--- >可移動(dòng)存儲(chǔ)介質(zhì)】的部分展示烧颖。
操作系統(tǒng)內(nèi)存布局:
操作系統(tǒng)內(nèi)部布局

操作系統(tǒng)內(nèi)存的堆棧:

棧區(qū)(stack):由編譯器自動(dòng)分配釋放 弱左,存放函數(shù)的參數(shù)值,局部變量的值等炕淮。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧拆火。
堆區(qū) (heap):一般由程序員分配釋放, 若程序員不釋放涂圆,程序結(jié)束時(shí)可能由OS回收 们镜。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表

棧是為執(zhí)行線程留出的內(nèi)存空間(當(dāng)線程創(chuàng)建的時(shí)候润歉,操作系統(tǒng)會(huì)為每個(gè)系統(tǒng)級(jí)的線程分配棧)模狭;
棧頂會(huì)為局部變量和數(shù)據(jù)預(yù)留塊,當(dāng)函數(shù)執(zhí)行完畢卡辰,塊就沒有用了胞皱,可能在下次的函數(shù)調(diào)用的時(shí)候再被使用邪意,棧通常都是采用后進(jìn)先出的方式預(yù)留空間九妈;因此最近的保留塊通常最先被釋放,從棧中釋放塊不過是指針的偏移(這里和數(shù)據(jù)結(jié)構(gòu)中的棧的意思類似)

堆的數(shù)據(jù)結(jié)構(gòu)并不是由系統(tǒng)支持的雾鬼,而是由函數(shù)庫提供的基本的malloc/realloc/free函數(shù)維護(hù)了一套內(nèi)部的堆數(shù)據(jù)結(jié)構(gòu)(所以才需要程序員自己釋放內(nèi)存萌朱,否則會(huì)造成內(nèi)存泄漏);

堆包含了一個(gè)鏈表來維護(hù)已用和空閑的內(nèi)存塊策菜;
申請(qǐng)內(nèi)存:
當(dāng)程序需要在堆中分配內(nèi)存的時(shí)候晶疼,會(huì)從內(nèi)部堆中尋找可用的內(nèi)存空間酒贬,通過鏈表找到符合大小的內(nèi)存塊(鏈表遍歷的方向是由低地址指向高地址),但是由于堆是不連續(xù)的內(nèi)存區(qū)域翠霍,當(dāng)找不到合適的內(nèi)存區(qū)域的時(shí)候锭吨,則會(huì)利用系統(tǒng)調(diào)用來動(dòng)態(tài)增加程序數(shù)據(jù)段的內(nèi)存大小寒匙;
釋放內(nèi)存:
當(dāng)系統(tǒng)受到程序的釋放內(nèi)存的申請(qǐng)的時(shí)候零如,會(huì)遍歷該鏈表,尋找第一個(gè)空間大于所申請(qǐng)的堆結(jié)點(diǎn)锄弱,然后該結(jié)點(diǎn)會(huì)從鏈表中刪除考蕾,并將該結(jié)點(diǎn)的空間釋放給內(nèi)存,這片內(nèi)存空間又會(huì)返回到堆結(jié)構(gòu)中会宪,會(huì)經(jīng)過內(nèi)存塊的組合肖卧,以便適合下次內(nèi)存分配申請(qǐng);(這里面如果沒有管理內(nèi)存分配在釋放內(nèi)存時(shí)很容易會(huì)造成內(nèi)存碎片)

操作系統(tǒng)中的jvm

為什么jvm的內(nèi)存是分布在操作系統(tǒng)的堆中呢掸鹅??因?yàn)椴僮飨到y(tǒng)的棧是操作系統(tǒng)管理的巍沙,它隨時(shí)會(huì)被回收,所以如果jvm放在棧中赎瞎,那java的一個(gè)null對(duì)象就很難確定會(huì)被誰回收了,那gc的存在就一點(diǎn)意義都沒有了务甥,而要對(duì)棧做到自動(dòng)釋放也是jvm需要考慮的牡辽,所以放在堆中就最合適不過了。

操作系統(tǒng)+jvm的內(nèi)存簡單布局

JVM 的內(nèi)存主要分為3個(gè)分區(qū)

堆區(qū)(Heap)-- 只存對(duì)象(數(shù)組)本身(引用類型的數(shù)據(jù))敞临,不存基本類型和對(duì)象的引用态辛。JVM只有一個(gè)堆區(qū),這個(gè)“堆”是動(dòng)態(tài)內(nèi)存分配意義上的堆——用于管理動(dòng)態(tài)生命周期的內(nèi)存區(qū)域挺尿。JVM的堆被同一個(gè)JVM實(shí)例中的所有Java線程共享奏黑,它通常由某種自動(dòng)內(nèi)存管理機(jī)制所管理,這種機(jī)制通常叫做“垃圾回收”(garbage collection编矾,GC)熟史。JVM規(guī)范并不強(qiáng)制要求JVM實(shí)現(xiàn)采用哪種GC算法。
棧區(qū)(Stack)-- 棧中只保存基礎(chǔ)數(shù)據(jù)類型的對(duì)象和對(duì)象引用窄俏。每個(gè)線程一個(gè)棧區(qū)蹂匹,每個(gè)棧區(qū)中的數(shù)據(jù)都是私有的,其他棧不能訪問凹蜈。棧內(nèi)有幀(方法調(diào)用會(huì)生成棧幀)分三個(gè)部分:基本類型變量區(qū)限寞,執(zhí)行環(huán)境上下文忍啸,操作指令區(qū)。
方法區(qū) -- 又叫靜態(tài)區(qū)履植,跟堆一樣计雌,被所有線程共享。方法區(qū)包含所有的class和static變量玫霎。方法區(qū)包含的都是在整個(gè)程序中永遠(yuǎn)唯一的元素白粉。如:class,satic鼠渺。


運(yùn)行時(shí)jvm的處理

細(xì)化到增加jvm內(nèi)部的處理和pc寄存器的配合時(shí)鸭巴,可見,無論是在虛擬機(jī)中還是在我們虛擬機(jī)所寄宿的操作系統(tǒng)中功能目的是一致的拦盹,計(jì)算機(jī)上的pc寄存器是計(jì)算機(jī)上的硬件鹃祖,本來就是屬于計(jì)算機(jī),計(jì)算機(jī)用pc寄存器來存放“偽指令”或地址普舆,而相對(duì)于虛擬機(jī)恬口,pc寄存器它表現(xiàn)為一塊內(nèi)存(一個(gè)字長,虛擬機(jī)要求字長最小為32位)沼侣,虛擬機(jī)的pc寄存器的功能也是存放偽指令祖能,更確切的說存放的是將要執(zhí)行指令的地址,它甚至可以是操作系統(tǒng)指令的本地地址蛾洛,當(dāng)虛擬機(jī)正在執(zhí)行的方法是一個(gè)本地方法的時(shí)候养铸,jvm的pc寄存器存儲(chǔ)的值是undefined,所以應(yīng)該很明確的知道钞螟,虛擬機(jī)的pc寄存器是用于存放下一條將要執(zhí)行的指令的地址(字節(jié)碼流)谎碍。

當(dāng)一個(gè)classLoder啟動(dòng)的時(shí)候,classLoader的生存地點(diǎn)在jvm中的堆拯啦,然后它會(huì)去主機(jī)硬盤上將A.class裝載到j(luò)vm的方法區(qū)褒链,方法區(qū)中的這個(gè)字節(jié)文件會(huì)被虛擬機(jī)拿來new A字節(jié)碼()笋敞,然后在堆內(nèi)存生成了一個(gè)A字節(jié)碼的對(duì)象夯巷,然后A字節(jié)碼這個(gè)內(nèi)存文件有兩個(gè)引用一個(gè)指向A的class對(duì)象,一個(gè)指向加載自己的classLoader喷兼,如下圖季惯。


image.png

方法區(qū)中的字節(jié)碼內(nèi)存塊勉抓,除了記錄一個(gè)class自己的class對(duì)象引用和一個(gè)加載自己的ClassLoader引用之外候学,還記錄了以下信息。


image.png

從上面的圖隐圾,不難發(fā)現(xiàn)暇藏,原來jvm的設(shè)計(jì)的模型其實(shí)就是操作系統(tǒng)的模型盐碱,基于操作系統(tǒng)的角度沪伙,jvm就是個(gè)java.exe/javaw.exe焰坪,也就是一個(gè)應(yīng)用,而基于class文件來說儒恋,jvm就是個(gè)操作系統(tǒng)诫尽,而jvm的方法區(qū)炬守,也就相當(dāng)于操作系統(tǒng)的硬盤區(qū),所以他也叫permanent區(qū)曹洽,因?yàn)檫@個(gè)單詞是永久的意思辽剧,也就是永久區(qū),我們的磁盤就是不斷電的永久區(qū)偷崩。而java棧和操作系統(tǒng)棧是一致的阐斜,無論是生長方向還是管理的方式诀紊,至于堆,雖然概念上一致目標(biāo)也一致到推,分配內(nèi)存的方式也一直(new,或者malloc等等)莉测,但是由于他們的管理方式不同唧喉,jvm是gc回收八孝,而操作系統(tǒng)是程序員手動(dòng)釋放,所以在算法上有很多的差異子姜。

堆棧的概念有2種楼入,通常除了內(nèi)存上面的概念嘉熊,還有數(shù)據(jù)結(jié)構(gòu)里面的概念,兩者不完全相同凫佛。簡單的概念區(qū)分如下:

棧(操作系統(tǒng)-內(nèi)存):由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值晨炕,局部變量的值等厚满。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧碧磅, 他們通常都是被調(diào)用時(shí)處于存儲(chǔ)空間中鲸郊,調(diào)用完畢立即釋放
堆(操作系統(tǒng)-內(nèi)存): 一般由程序員分配釋放, 若程序員不釋放秆撮,程序結(jié)束時(shí)可能由OS回收,分配方式倒是類似于鏈表盗蟆。生命周期由虛擬機(jī)的垃圾回收算法來決定(并不是一旦成為孤兒對(duì)象就能被回收)喳资。所以調(diào)用這些對(duì)象的速度要相對(duì)來得低一些
堆(數(shù)據(jù)結(jié)構(gòu)):堆可以被看成是一棵樹腾供,如:堆排序
棧(數(shù)據(jù)結(jié)構(gòu)):一種后進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)

參考資料:
JVM與操作系統(tǒng)
https://zhuanlan.zhihu.com/p/44401058
操作系統(tǒng)中堆和棧的區(qū)別
https://blog.csdn.net/SpeedMe/article/details/22943191
java之jvm學(xué)習(xí)筆記十三(jvm基本結(jié)構(gòu))
https://blog.csdn.net/yfqnihao/article/details/8289363
JVM的內(nèi)存區(qū)域劃分
https://www.cnblogs.com/dolphin0520/p/3613043.html
操作系統(tǒng)之堆和棧的區(qū)別
https://www.cnblogs.com/George1994/p/6399895.html
JVM學(xué)習(xí)(2)——技術(shù)文章里常說的堆伴鳖,棧,堆棧到底是什么搞疗,從os的角度總結(jié)
https://www.cnblogs.com/kubixuesheng/p/5202561.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末匿乃,一起剝皮案震驚了整個(gè)濱河市休吠,隨后出現(xiàn)的幾起案子瘤礁,更是在濱河造成了極大的恐慌,老刑警劉巖岩调,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件号枕,死亡現(xiàn)場離奇詭異,居然都是意外死亡钝腺,警方通過查閱死者的電腦和手機(jī)赞厕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門毫目,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诲侮,“玉大人,你說我怎么就攤上這事刮便〗悖” “怎么了久信?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長入客。 經(jīng)常有香客問我桌硫,道長啃炸,這世上最難降的妖魔是什么南用? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任掏湾,我火速辦了婚禮融击,結(jié)果婚禮上尊浪,老公的妹妹穿的比我還像新娘。我一直安慰自己拇涤,他們只是感情好工育,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布搓彻。 她就那樣靜靜地躺著嘱朽,像睡著了一般搪泳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上岸军,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天佣谐,我揣著相機(jī)與錄音狭魂,去河邊找鬼。 笑死雌澄,一個(gè)胖子當(dāng)著我的面吹牛镐牺,可吹牛的內(nèi)容都是我干的魁莉。 我是一名探鬼主播卒废,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼宅粥!你這毒婦竟也來了秽梅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤环壤,失蹤者是張志新(化名)和其女友劉穎郑现,沒想到半個(gè)月后接箫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體朵诫,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡剪返,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年脱盲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宾毒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乙各,死狀恐怖幢竹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情焕毫,我是刑警寧澤驶乾,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布级乐,位于F島的核電站县匠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏贼穆。R本人自食惡果不足惜兰粉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玖姑。 院中可真熱鬧愕秫,春花似錦、人聲如沸客峭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舔琅。三九已至,卻和暖如春洲劣,著一層夾襖步出監(jiān)牢的瞬間备蚓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國打工囱稽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留郊尝,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓战惊,卻偏偏與公主長得像况凉,于是被迫代替她去往敵國和親刁绒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子傻盟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容