自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JVM 的棧上分配、TLAB、PLAB 有啥區(qū)別?

開發(fā) 前端
一般情況下,每個(gè)線程如果有新建的對(duì)象,那么會(huì)跟 JVM 申請(qǐng)?jiān)诙焉蟿?chuàng)建對(duì)應(yīng)的對(duì)象,而線程的棧則存儲(chǔ)了指向堆對(duì)象的指針。每當(dāng)一個(gè)線程想創(chuàng)建一個(gè)對(duì)象時(shí),首先會(huì)請(qǐng)求 JVM,之后 JVM 進(jìn)行協(xié)調(diào),創(chuàng)建完成之后再告訴線程,線程最后將引用放到棧中。

?大家好,我是樹哥。

我們?cè)趯W(xué)習(xí) G1 回收器的時(shí)候,一般我們都會(huì)接觸到 TLAB 和 PLAB 這兩個(gè)術(shù)語。它們都是為了提高內(nèi)存分配效率而存在的,但它們和棧上分配有什么區(qū)別呢?今天,就讓樹哥帶著大家盤一盤。

圖片

棧上分配

稍微了解過 Java 虛擬機(jī)內(nèi)存結(jié)構(gòu)的同學(xué)都知道,在 Java 虛擬機(jī)中有兩個(gè)關(guān)鍵的存儲(chǔ)數(shù)據(jù)節(jié)點(diǎn),那就是:堆與棧。

其中堆是所有線程共享的一塊內(nèi)存,幾乎所有對(duì)象的分配都在這塊內(nèi)存中。而棧則是線程自己私有的,只存儲(chǔ)線程自己的局部變量等信息。每個(gè)線程都有自己的棧,棧信息無法在線程之間共享。

圖片

一般情況下,每個(gè)線程如果有新建的對(duì)象,那么會(huì)跟 JVM 申請(qǐng)?jiān)诙焉蟿?chuàng)建對(duì)應(yīng)的對(duì)象,而線程的棧則存儲(chǔ)了指向堆對(duì)象的指針。每當(dāng)一個(gè)線程想創(chuàng)建一個(gè)對(duì)象時(shí),首先會(huì)請(qǐng)求 JVM,之后 JVM 進(jìn)行協(xié)調(diào),創(chuàng)建完成之后再告訴線程,線程最后將引用放到棧中。

在對(duì)象創(chuàng)建的這個(gè)過程,堆和棧之間的關(guān)系就像是列車的中央調(diào)度室和火車的關(guān)系。每次線程需要分配內(nèi)存空間,都需要去到堆去申請(qǐng)空間,會(huì)耗費(fèi)不少時(shí)間和精力。

這個(gè)時(shí)候有人就發(fā)現(xiàn),線程的有些對(duì)象其實(shí)別人也不會(huì)訪問到,放在堆中貌似也沒什么大作用。于是他提出:對(duì)于這些其他線程不會(huì)訪問的對(duì)象,我們能不能讓線程自己分配在它自己的??臻g上?這樣不就可以節(jié)省不少交互時(shí)間了么!

這個(gè)方法確實(shí)不錯(cuò),如果能實(shí)現(xiàn)應(yīng)該可以提高對(duì)象創(chuàng)建的時(shí)間,提高虛擬機(jī)的運(yùn)行效率。

但問題是:我怎么知道哪些對(duì)象可以分配在棧上,哪些不行呢?

其實(shí)聰明的軟件工程師們?cè)缇徒鉀Q了這個(gè)問題了,他們新造了一個(gè)名字:逃逸分析。

那么什么是逃逸分析呢?

從字面意思上來講,逃逸分析的目的是判斷對(duì)象的作用域是否有可能逃出函數(shù)體。例如下面的代碼就顯示了一個(gè)逃逸的對(duì)象:

private static User user;
private static void hello(){
u = new User();
u.name = "java.top.select";
u.website = "http://www.shuyi.me";
}

對(duì)象實(shí)例 user 是類的成員變量,可以被任何線程訪問,因此它屬于逃逸對(duì)象。但如果我們將代碼稍微改動(dòng)一下,該對(duì)象就可以線程非逃逸的了。

private static void hello(){
User u = new User();
u.name = "java.top.select";
u.website = "http://www.shuyi.me";
}

可以看到 user 實(shí)例作用域只在 hello 函數(shù)中,不會(huì)被其他線程訪問到,也不會(huì)訪問。所以該 user 實(shí)例對(duì)象的作用域只在該函數(shù)中,因此它并未發(fā)生逃逸。對(duì)于這樣的情況,虛擬機(jī)就有可能將其分配在棧上,而不在堆上。

看到這里,我相信許多人都應(yīng)該明白了什么是棧上分配了。簡(jiǎn)單點(diǎn)說,就是將本來應(yīng)該分配在堆中的對(duì)象,讓其分配在線程私有的棧上。通過這種方式,減少垃圾回收的壓力,提高虛擬機(jī)的運(yùn)行效率。

TLAB

TLAB(Thread Local Allocation Buffer),即線程本地分配緩存。這是一塊線程專用的內(nèi)存分配區(qū)域,TLAB 占用的是 eden 區(qū)的空間。在 TLAB 啟用的情況下(默認(rèn)開啟),JVM 會(huì)為每一個(gè)線程分配一塊 TLAB 區(qū)域。

那么問什么需要 TLAB 呢?這是為了加速對(duì)象的分配!

由于對(duì)象一般分配在堆上,而堆事線程共用的,因此可能會(huì)有多個(gè)線程在堆上申請(qǐng)空間,而每一次的對(duì)象分配都必須線程同步,這樣會(huì)降低內(nèi)存分配的效率。

考慮到對(duì)象分配是非常常見的操作,于是 JVM 使用 TLAB 這樣的線程轉(zhuǎn)悠區(qū)域來避免多線程沖突,提高對(duì)象分配效率。

為了不至于導(dǎo)致 Eden 區(qū)被填充滿,因此 TLAB 空間一般不會(huì)太大。因此大對(duì)象有可能無法在 TLAB 分配,只能直接分配到堆上。這其實(shí)是一種折中的設(shè)計(jì)哲學(xué),因?yàn)榇蠖鄶?shù)分配的對(duì)象都比較小,因此 TLAB 空間能滿足大多數(shù)的需求。

PLAB

PLAB(Promotion Local Allocation Buffers),即晉升本地分配緩存。PLAB 的作用于 TLAB 類似,都是為了加速對(duì)象分配效率,避免多線程競(jìng)爭(zhēng)而誕生的。 只不過 PLAB 是應(yīng)用于對(duì)象晉升到 Survivor 區(qū)或老年代。與 TLAB 類似,每個(gè)線程都有獨(dú)立的 PLAB 區(qū)。

對(duì)象內(nèi)存分配流程

對(duì)于棧上分配與 TLAB 而言,其是有一定關(guān)系的。在進(jìn)行對(duì)象內(nèi)存分配的時(shí)候,首先會(huì)嘗試進(jìn)行棧上分配,接著嘗試進(jìn)行 TLAB 分配,接著判斷是否可以直接進(jìn)入老年代,最后不行的話再在 eden 區(qū)分配,如下圖所示。

圖片

圖片來自網(wǎng)絡(luò)

總結(jié)

了解完棧上分配、TLAB、PLAB 之后,我們基本上可以清晰地回答如下問題。

什么是棧上分配,它解決什么問題?

棧上分配指的是對(duì)象直接在線程棧幀中進(jìn)行分配,而不在堆中分配。它主要是為了解決多線程對(duì)象分配的低效問題,通過在棧上分配內(nèi)存,避免了多線程之間的沖突,提高了對(duì)象的分配效率。但要注意的是,其只能分配較小對(duì)象,并且該對(duì)象必須不被其他對(duì)象線程引用。

什么是 TLAB,它解決什么問題?

TLAB 指的是線程本地分配緩存,其對(duì)應(yīng) Eden 區(qū)的某個(gè)區(qū)域,但這塊區(qū)域只可以被該線程使用。

棧上分配和 TLAB 有啥區(qū)別?

TLAB 可以理解成是棧上分配的升級(jí)版本。棧上分配的對(duì)象只能被線程本身訪問,但 TLAB 的對(duì)象可以被其他對(duì)象讀取,但應(yīng)該無法操作。通過 TLAB,它解決了部分需要多線程訪問的對(duì)象分配效率問題,進(jìn)一步提升了 JVM 的對(duì)象分配效率。

什么是 PLAB,它解決了什么問題?

PLAB 是為了在對(duì)象晉升到 Survivor 區(qū)或老年代的時(shí)候,提升對(duì)象的分配效率。其優(yōu)化思路與 TLAB 類似,只是應(yīng)用的地方不同。

參考資料

JVM 對(duì)象分配之棧上分配 & TLAB 分配 - 掘金

棧上分配技術(shù),這么高端的技術(shù)到底是啥?

JVM 內(nèi)存分配機(jī)制之棧上分配與 TLAB 的區(qū)別 - 騰訊云開發(fā)者社區(qū) - 騰訊云?

責(zé)任編輯:武曉燕 來源: 樹哥聊編程
相關(guān)推薦

2022-12-12 08:42:06

Java對(duì)象棧內(nèi)存

2021-07-28 21:49:01

JVM對(duì)象內(nèi)存

2021-09-28 07:12:09

函數(shù)內(nèi)存

2021-03-22 11:51:22

Java內(nèi)存棧上

2010-09-25 15:40:52

配置JVM內(nèi)存

2012-01-11 10:45:57

JavaJVM

2022-01-17 10:07:05

PodmanDocker容器

2023-01-06 10:52:30

SQL索引存儲(chǔ)

2020-05-27 21:13:27

JavaJVM內(nèi)存

2018-04-08 08:45:53

對(duì)象內(nèi)存策略

2021-07-30 07:22:51

JVM虛擬機(jī)棧 Stack

2021-04-19 09:27:03

Java線程操作系統(tǒng)

2010-09-27 08:38:49

JVM堆JVM棧

2009-07-09 10:01:26

設(shè)置JVM內(nèi)存分配

2017-04-05 08:59:43

AMDInte平臺(tái)

2021-12-31 09:23:22

SDNSD-WAN網(wǎng)絡(luò)技術(shù)

2015-02-13 10:24:51

微信

2024-01-02 10:31:14

JVM內(nèi)存整體

2023-03-26 00:43:42

JVM對(duì)象測(cè)試

2021-10-18 09:08:27

Go分段棧連續(xù)棧
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)