jvm┃java內(nèi)存區(qū)域,跳槽大廠必會(huì)知識(shí)點(diǎn)!
目錄
前言
正文
1.程序計(jì)數(shù)器
2.虛擬機(jī)棧
3.本地方法棧
4.堆
5.方法區(qū)
6.直接內(nèi)存
結(jié)語

前言
在java的使用過程當(dāng)中,我們會(huì)發(fā)現(xiàn)java的內(nèi)存是自己釋放的,并不像C、C++代碼那樣,每一塊兒內(nèi)存都需要程序員自己去維護(hù),但是在如此便捷的同時(shí)可能也會(huì)出現(xiàn)很多問題,比如內(nèi)存溢出,內(nèi)存泄漏更不好排查了,所以今天的文章中,moon會(huì)帶大家先了解java的內(nèi)存區(qū)域的到底是怎樣的,以及各個(gè)組件的作用是什么,讓你一點(diǎn)一點(diǎn)翻越虛擬機(jī)內(nèi)存管理這座大山。

正文
我們先來看一張圖:

這張圖就是一個(gè)java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)圖,深色區(qū)域代表是線程共享的區(qū)域,java程序在運(yùn)行的過程中會(huì)把他管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域,每一塊兒的數(shù)據(jù)區(qū)域所負(fù)責(zé)的功能都是不同的,他們也有不同的創(chuàng)建時(shí)間和銷毀時(shí)間,本文將會(huì)從這張圖開始一一展開,清晰的告訴你每一個(gè)模塊的作用。
1.程序計(jì)數(shù)器
程序計(jì)數(shù)器就像是控制城市交通的紅綠燈一樣,是整個(gè)系統(tǒng)的中樞。在jvm中,它就是程序控制流的指示器,循環(huán),跳轉(zhuǎn),異常處理,線程的恢復(fù)等工作都需要依賴程序計(jì)數(shù)器去完成。
程序計(jì)數(shù)器是線程私有的,它的生命周期是和線程保持一致的,我們知道,N個(gè)核心數(shù)的CPU在同一時(shí)刻,最多有N個(gè)線程同時(shí)運(yùn)行,在我們真實(shí)的使用過程中可能會(huì)創(chuàng)建很多線程,jvm的多線程其實(shí)是通過線程輪流切換,分配處理器執(zhí)行時(shí)間來實(shí)現(xiàn)的。既然涉及的線程切換,所以每條線程必須有一個(gè)獨(dú)立的程序計(jì)數(shù)器。
2.虛擬機(jī)棧
虛擬機(jī)棧,其描述的就是線程內(nèi)存模型,也可以稱作線程棧,也是每個(gè)線程私有的,生命周期與線程保持一致。在每個(gè)方法執(zhí)行的時(shí)候,jvm都會(huì)同步創(chuàng)建一個(gè)棧幀去存儲(chǔ)局部變量表,操作數(shù)棧,動(dòng)態(tài)連接,方法出口等信息。一個(gè)方法的生命周期就貫徹了一個(gè)棧幀從入棧到出棧的全部過程。 局部變量表應(yīng)該是我們接觸的最多的,里面存儲(chǔ)了java的8大基本數(shù)據(jù)類型(byte、short、char、int、float、long、double、boolean)、對(duì)象引用(reference類型,不是對(duì)象本身,是指向?qū)ο蟮囊?和returnAddress類型(指向一條字節(jié)碼指令的地址)。局部變量表的存儲(chǔ)單位是局部變量槽(slot),long和double類型會(huì)占據(jù)兩個(gè)變量槽,其余類型只占用一個(gè),但是每一個(gè)變量槽的大小是由jvm自己決定的。
3.本地方法棧
本地方法棧的概念很好理解,我們知道,java底層用了很多c的代碼去實(shí)現(xiàn),而其調(diào)用c端的方法上都會(huì)有native,代表本地方法服務(wù),而本地方法棧就是為其服務(wù)的。
4.堆
堆可以說是jvm中最大的一塊兒內(nèi)存區(qū)域了,它是所有線程共享的,不管你是初學(xué)者還是資深開發(fā),多少都會(huì)聽說過堆,畢竟幾乎所有的對(duì)象都會(huì)在堆中分配。
我們先從分配內(nèi)存的角度看看堆是怎么樣的:
其實(shí)這就是一個(gè)最真實(shí)的堆,可能有些同學(xué)會(huì)覺得我說的不對(duì),應(yīng)該還有新生代,老年代,永久代,伊甸區(qū),servivor區(qū)等等。這種說法基于某種邏輯上說是對(duì)的,但是并不是標(biāo)準(zhǔn),它只是某些垃圾回收器的設(shè)計(jì)理念,需要新生代,老年代收集器搭配才能工作。
我們來說說TLAB(thread local allocation buffer),TLAB的數(shù)量和線程數(shù)是一一對(duì)應(yīng)的,也就是說,TLAB是線程私有的,在堆空間中分配,對(duì)象會(huì)首先存放在這個(gè)線程私有的TLAB中,可以提升線程分配的效率。
5.方法區(qū)
方法區(qū)也是所有線程共享的區(qū)域,它存儲(chǔ)了被jvm加載的類型信息、常量、靜態(tài)變量等數(shù)據(jù)。
運(yùn)行時(shí)常量池就是方法區(qū)的一部分,編譯期生成的各種字面量與符號(hào)引用就存儲(chǔ)在其中。
6.直接內(nèi)存
這部分?jǐn)?shù)據(jù)并不是jvm運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,nio就會(huì)使用到直接內(nèi)存,也可以說堆外內(nèi)存,通常會(huì)配合虛引用一起去使用,就是為了資源釋放,會(huì)將堆外內(nèi)存開辟空間的信息存儲(chǔ)到一個(gè)隊(duì)列中,然后GC會(huì)去清理這部分空間。
堆外內(nèi)存優(yōu)勢(shì)在 IO 操作上,對(duì)于網(wǎng)絡(luò) IO,使用 Socket 發(fā)送數(shù)據(jù)時(shí),能夠節(jié)省堆內(nèi)存到堆外內(nèi)存的數(shù)據(jù)拷貝,所以性能更高。看過 Netty 源碼的同學(xué)應(yīng)該了解,Netty 使用堆外內(nèi)存池來實(shí)現(xiàn)零拷貝技術(shù)。對(duì)于磁盤 IO 時(shí),也可以使用內(nèi)存映射,來提升性能。另外,更重要的幾乎不用考慮堆內(nèi)存煩人的 GC 問題。但是既然是內(nèi)存。也會(huì)受到本機(jī)總內(nèi)存的限制,

結(jié)語
今天和大家聊了聊java內(nèi)存區(qū)域是怎樣的,而這部分內(nèi)容都是比較標(biāo)準(zhǔn)化得一個(gè)體現(xiàn),并沒有摻雜垃圾回收相關(guān)的知識(shí),也沒有摻雜jvm具體實(shí)現(xiàn)的相關(guān)邏輯,我們知道這是一個(gè)基礎(chǔ)的架構(gòu),我們?cè)陂_發(fā)中默認(rèn)使用的jvm是hotspot,它是SunJDK和OpenJDK中所帶的虛擬機(jī),也是目前使用范圍最廣的Java虛擬機(jī),他們都是基于jvm規(guī)范去開發(fā)的,所以了解規(guī)范之后再去學(xué)其他深入的實(shí)現(xiàn),不要各個(gè)知識(shí)點(diǎn)紊亂的去學(xué)。
下一篇文章我會(huì)和大家聊聊對(duì)象的創(chuàng)建和對(duì)象的內(nèi)存布局相關(guān)知識(shí)。
下期見,我是moon,記得關(guān)注點(diǎn)贊~

mysql┃多個(gè)角度說明sql優(yōu)化,讓你吊打面試官!

mysql|聊完了mysql索引,面試官直接給我漲了2000!
