欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Java對象的內(nèi)存分配過程是如何保證線程安全的?-創(chuàng)新互聯(lián)

Java作為一種面向?qū)ο蟮模缙脚_語言,其對象、內(nèi)存等一直是比較難的知識點,所以,即使是一個Java的初學者,也一定或多或少的對JVM有一些了解。可以說,關(guān)于JVM的相關(guān)知識,基本是每個Java開發(fā)者必學的知識點,也是面試的時候必考的知識點。

從網(wǎng)站建設(shè)到定制行業(yè)解決方案,為提供做網(wǎng)站、成都網(wǎng)站制作服務(wù)體系,各種行業(yè)企業(yè)客戶提供網(wǎng)站建設(shè)解決方案,助力業(yè)務(wù)快速發(fā)展。創(chuàng)新互聯(lián)將不斷加快創(chuàng)新步伐,提供優(yōu)質(zhì)的建站服務(wù)。

在JVM的內(nèi)存結(jié)構(gòu)中,比較常見的兩個區(qū)域就是堆內(nèi)存和棧內(nèi)存(如無特指,本文提到的棧均指的是虛擬機棧),關(guān)于堆和棧的區(qū)別,很多開發(fā)者也是如數(shù)家珍,有很多書籍,或者網(wǎng)上的文章大概都是這樣介紹的:

1、堆是線程共享的內(nèi)存區(qū)域,棧是線程獨享的內(nèi)存區(qū)域。

2、堆中主要存放對象實例,棧中主要存放各種基本數(shù)據(jù)類型、對象的引用。

但是,作者可以很負責任的告訴大家,以上兩個結(jié)論均不是完全正確的。

本文首先帶大家了解一下為什么我會說“堆是線程共享的內(nèi)存區(qū)域,棧是線程獨享的內(nèi)存區(qū)域。”這句話并不完全正確!?關(guān)于JVM內(nèi)存結(jié)構(gòu)的相關(guān)知識,大家可以閱讀JVM內(nèi)存結(jié)構(gòu) VS Java內(nèi)存模型 VS Java對象模型、萬萬沒想到,JVM內(nèi)存結(jié)構(gòu)的面試題可以問的這么難?等文章。

我們知道,Java是一門面向?qū)ο蟮恼Z言,我們在Java中使用的對象都需要被創(chuàng)建出來,在Java中,創(chuàng)建一個對象的方法有很多種,但是無論如何,對象在創(chuàng)建過程中,都需要進行內(nèi)存分配。

對象的內(nèi)存分配過程中,主要是對象的引用指向這個內(nèi)存區(qū)域,然后進行初始化操作。

但是,因為堆是全局共享的,因此在同一時間,可能有多個線程在堆上申請空間,那么,在并發(fā)場景中,如果兩個線程先后把對象引用指向了同一個內(nèi)存區(qū)域,怎么辦。

Java對象的內(nèi)存分配過程是如何保證線程安全的?

為了解決這個并發(fā)問題,對象的內(nèi)存分配過程就必須進行同步控制。但是我們都知道,無論是使用哪種同步方案(實際上虛擬機使用的可能是CAS),都會影響內(nèi)存的分配效率。

而Java對象的分配是Java中的高頻操作,所有,人們想到另外一個辦法來提升效率。這里我們重點說一個HotSpot虛擬機的方案:

每個線程在Java堆中預(yù)先分配一小塊內(nèi)存,然后再給對象分配內(nèi)存的時候,直接在自己這塊”私有”內(nèi)存中分配,當這部分區(qū)域用完之后,再分配新的”私有”內(nèi)存。

這種方案被稱之為TLAB分配,即Thread Local Allocation Buffer。這部分Buffer是從堆中劃分出來的,但是是本地線程獨享的。

TLAB是虛擬機在堆內(nèi)存的eden劃分出來的一塊專用空間,是線程專屬的。在虛擬機的TLAB功能啟動的情況下,在線程初始化時,虛擬機會為每個線程分配一塊TLAB空間,只給當前線程使用,這樣每個線程都單獨擁有一個空間,如果需要分配內(nèi)存,就在自己的空間上分配,這樣就不存在競爭的情況,可以大大提升分配效率。

注意到上面的描述中"線程專屬"、"只給當前線程使用"、"每個線程單獨擁有"的描述了嗎?

所以說,因為有了TLAB技術(shù),堆內(nèi)存并不是完完全全的線程共享,其eden區(qū)域中還是有一部分空間是分配給線程獨享的。

這里值得注意的是,我們說TLAB是線程獨享的,但是只是在“分配”這個動作上是線程獨享的,至于在讀取、垃圾回收等動作上都是線程共享的。而且在使用上也沒有什么區(qū)別

Java對象的內(nèi)存分配過程是如何保證線程安全的?

也就是說,雖然每個線程在初始化時都會去堆內(nèi)存中申請一塊TLAB,并不是說這個TLAB區(qū)域的內(nèi)存其他線程就完全無法訪問了,其他線程的讀取還是可以的,只不過無法在這個區(qū)域中分配內(nèi)存而已。

并且,在TLAB分配之后,并不影響對象的移動和回收,也就是說,雖然對象剛開始可能通過TLAB分配內(nèi)存,存放在Eden區(qū),但是還是會被垃圾回收或者被移到Survivor Space、Old Gen等。

Java對象的內(nèi)存分配過程是如何保證線程安全的?

還有一點需要注意的是,我們說TLAB是在eden區(qū)分配的,因為eden區(qū)域本身就不太大,而且TLAB空間的內(nèi)存也非常小,默認情況下僅占有整個Eden空間的1%。所以,必然存在一些大對象是無法在TLAB直接分配。

遇到TLAB中無法分配的大對象,對象還是可能在eden區(qū)或者老年代等進行分配的,但是這種分配就需要進行同步控制,這也是為什么我們經(jīng)常說:小的對象比大的對象分配起來更加高效。

雖然在一定程度上,TLAB大大的提升了對象的分配速度,但是TLAB并不是就沒有任何問題的。

前面我們說過,因為TLAB內(nèi)存區(qū)域并不是很大,所以,有可能會經(jīng)常出現(xiàn)不夠的情況。在《實戰(zhàn)Java虛擬機》中有這樣一個例子:

比如一個線程的TLAB空間有100KB,其中已經(jīng)使用了80KB,當需要再分配一個30KB的對象時,就無法直接在TLAB中分配,遇到這種情況時,有兩種處理方案:

1、如果一個對象需要的空間大小超過TLAB中剩余的空間大小,則直接在堆內(nèi)存中對該對象進行內(nèi)存分配。

2、如果一個對象需要的空間大小超過TLAB中剩余的空間大小,則廢棄當前TLAB,重新申請TLAB空間再次進行內(nèi)存分配。

以上兩個方案各有利弊,如果采用方案1,那么就可能存在著一種極端情況,就是TLAB只剩下1KB,就會導致后續(xù)需要分配的大多數(shù)對象都需要在堆內(nèi)存直接分配。

如果采用方案2,也有可能存在頻繁廢棄TLAB,頻繁申請TLAB的情況,而我們知道,雖然在TLAB上分配內(nèi)存是線程獨享的,但是TLAB內(nèi)存自己從堆中劃分出來的過程確實可能存在沖突的,所以,TLAB的分配過程其實也是需要并發(fā)控制的。而頻繁的TLAB分配就失去了使用TLAB的意義。

為了解決這兩個方案存在的問題,虛擬機定義了一個refill_waste的值,這個值可以翻譯為“大浪費空間”。

當請求分配的內(nèi)存大于refill_waste的時候,會選擇在堆內(nèi)存中分配。若小于refill_waste值,則會廢棄當前TLAB,重新創(chuàng)建TLAB進行對象內(nèi)存分配。

前面的例子中,TLAB總空間100KB,使用了80KB,剩余20KB,如果設(shè)置的refill_waste的值為25KB,那么如果新對象的內(nèi)存大于25KB,則直接堆內(nèi)存分配,如果小于25KB,則會廢棄掉之前的那個TLAB,重新分配一個TLAB空間,給新對象分配內(nèi)存。

TLAB功能是可以選擇開啟或者關(guān)閉的,可以通過設(shè)置-XX:+/-UseTLAB參數(shù)來指定是否開啟TLAB分配。

TLAB默認是eden區(qū)的1%,可以通過選項-XX:TLABWasteTargetPercent設(shè)置TLAB空間所占用Eden空間的百分比大小。

默認情況下,TLAB的空間會在運行時不斷調(diào)整,使系統(tǒng)達到最佳的運行狀態(tài)。如果需要禁用自動調(diào)整TLAB的大小,可以使用-XX:-ResizeTLAB來禁用,并且使用-XX:TLABSize來手工指定TLAB的大小。

TLAB的refill_waste也是可以調(diào)整的,默認值為64,即表示使用約為1/64空間大小作為refill_waste,使用參數(shù):-XX:TLABRefillWasteFraction來調(diào)整。

如果想要觀察TLAB的使用情況,可以使用參數(shù)-XX+PringTLAB 進行跟蹤。

為了保證對象的內(nèi)存分配過程中的線程安全性,HotSpot虛擬機提供了一種叫做TLAB(Thread Local Allocation Buffer)的技術(shù)。

在線程初始化時,虛擬機會為每個線程分配一塊TLAB空間,只給當前線程使用,當需要分配內(nèi)存時,就在自己的空間上分配,這樣就不存在競爭的情況,可以大大提升分配效率。

所以,“堆是線程共享的內(nèi)存區(qū)域”這句話并不完全正確,因為TLAB是堆內(nèi)存的一部分,他在讀取上確實是線程共享的,但是在內(nèi)存分配上,是線程獨享的。

TLAB的空間其實并不大,所以大對象還是可能需要在堆內(nèi)存中直接分配。那么,對象的內(nèi)存分配步驟就是先嘗試TLAB分配,空間不足之后,再判斷是否應(yīng)該直接進入老年代,然后再確定是再eden分配還是在老年代分配。

Java對象的內(nèi)存分配過程是如何保證線程安全的?

TLAB只是HotSpot虛擬機的一個優(yōu)化方案,Java虛擬機規(guī)范中也沒有關(guān)于TLAB的任何規(guī)定。所以,不代表所有的虛擬機都有這個特性。


本文的概述都是基于HotSpot虛擬機的,因為HotSpot虛擬機是目前最流行的虛擬機了,大多數(shù)默認情況下,我們討論的時候也都是基于HotSpot的。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

當前題目:Java對象的內(nèi)存分配過程是如何保證線程安全的?-創(chuàng)新互聯(lián)
網(wǎng)站地址:http://www.chinadenli.net/article0/gchio.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄網(wǎng)站設(shè)計公司企業(yè)網(wǎng)站制作網(wǎng)站策劃響應(yīng)式網(wǎng)站手機網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運營