日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java安全点_关于OopMap、SafePoint(安全点)以及安全区域

發(fā)布時(shí)間:2025/5/22 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java安全点_关于OopMap、SafePoint(安全点)以及安全区域 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.OopMap

之前我們提到,在正式的GC之前總是需要進(jìn)行可達(dá)性分析來(lái)查找內(nèi)存中所有存活的對(duì)象,以便GC能夠正確的回收已經(jīng)死亡的對(duì)象。那么對(duì)于一個(gè)十分復(fù)雜的系統(tǒng),每次GC的時(shí)候都要遍歷所有的引用肯定是不現(xiàn)實(shí)的。因?yàn)樵诳蛇_(dá)性分析的時(shí)候,需要進(jìn)行Stop The World,程序中的線程需要停止來(lái)配合可達(dá)性分析。就好像是你女朋友在打掃衛(wèi)生的時(shí)候(什么,你還沒(méi)有女朋友?這還能難道程序員了?new 一個(gè)啊!),肯定不會(huì)讓你走來(lái)走去的。所以,你肯定在內(nèi)心里也希望你女朋友打掃衛(wèi)生快一點(diǎn),因?yàn)槟愕陌螂滓呀?jīng)快要爆炸了。對(duì)于程序來(lái)說(shuō)有也一樣,也希望GC的時(shí)候快一點(diǎn),以便讓程序高效地完成工作。

所以,每次直接遍歷整個(gè)引用鏈肯定是不現(xiàn)實(shí)的。 為了應(yīng)對(duì)這種尷尬的問(wèn)題,最早有保守式GC和后來(lái)的準(zhǔn)確式GC。這里準(zhǔn)確式GC就會(huì)提到一個(gè)OopMap,用來(lái)保存類(lèi)型的映射表。

保守式GC

在進(jìn)行GC的時(shí)候,會(huì)從一些已知的位置(GC Roots)開(kāi)始掃描內(nèi)存,掃描到一個(gè)數(shù)字就判斷他是不是可能是指向GC堆中的一個(gè)指針(這里會(huì)涉及上下邊界檢查(GC堆的上下界是已知的)、對(duì)齊檢查(通常分配空間的時(shí)候會(huì)有對(duì)齊要求,假如說(shuō)是4字節(jié)對(duì)齊,那么不能被4整除的數(shù)字就肯定不是指針),之類(lèi)的。)。然后一直遞歸的掃描下去,最后完成可達(dá)性分析。這種模糊的判斷方法因?yàn)闊o(wú)法準(zhǔn)確判斷一個(gè)位置上是否是真的指向GC堆中的指針,所以被命名為保守式GC。這種可達(dá)性分析的方式因?yàn)椴恍枰獪?zhǔn)確的判斷出一個(gè)指針,所以效率快,但是也正因?yàn)檫@種特點(diǎn),他存在下面兩個(gè)明顯的缺點(diǎn):

因?yàn)槭悄:臋z查,所以對(duì)于一些已經(jīng)死掉的對(duì)象,很可能會(huì)被誤認(rèn)為仍有地方引用他們,GC也就自然不會(huì)回收他們,從而引起了無(wú)用的內(nèi)存占用,就是典型的占著茅坑不拉屎,造成資源浪費(fèi)。

由于不知道疑似指針是否真的是指針,所以它們的值都不能改寫(xiě);移動(dòng)對(duì)象就意味著要修正指針。換言之,對(duì)象就不可移動(dòng)了。有一種辦法可以在使用保守式GC的同時(shí)支持對(duì)象的移動(dòng),那就是增加一個(gè)間接層,不直接通過(guò)指針來(lái)實(shí)現(xiàn)引用,而是添加一層“句柄”(handle)在中間,所有引用先指到一個(gè)句柄表里,再?gòu)木浔碚业綄?shí)際對(duì)象。這樣,要移動(dòng)對(duì)象的話(huà),只要修改句柄表里的內(nèi)容即可。但是這樣的話(huà)引用的訪問(wèn)速度就降低了。Sun JDK的Classic VM用過(guò)這種全handle的設(shè)計(jì),但效果實(shí)在算不上好。

2.準(zhǔn)確式GC

與保守式GC相對(duì)的就是準(zhǔn)確式GC,何為準(zhǔn)確式GC?就是我們準(zhǔn)確的知道,某個(gè)位置上面是否是指針,對(duì)于java來(lái)說(shuō),就是知道對(duì)于某個(gè)位置上的數(shù)據(jù)是什么類(lèi)型的,這樣就可以判斷出所有的位置上的數(shù)據(jù)是不是指向GC堆的引用,包括棧和寄存器里的數(shù)據(jù)。

網(wǎng)上看了下說(shuō)是實(shí)現(xiàn)這種要求的方法有好幾種,但是在java中實(shí)現(xiàn)的方式是:從我外部記錄下類(lèi)型信息,存成映射表,在HotSpot中把這種映射表稱(chēng)之為OopMap,不同的虛擬機(jī)名稱(chēng)可能不一樣。

實(shí)現(xiàn)這種功能,需要虛擬機(jī)的解釋器和JIT編譯器支持,由他們來(lái)生成OopMap。生成這樣的映射表一般有兩種方式:

每次都遍歷原始的映射表,循環(huán)的一個(gè)個(gè)偏移量掃描過(guò)去;這種用法也叫“解釋式”;

為每個(gè)映射表生成一塊定制的掃描代碼(想像掃描映射表的循環(huán)被展開(kāi)的樣子),以后每次要用映射表就直接執(zhí)行生成的掃描代碼;這種用法也叫“編譯式”。

總而言之,GC開(kāi)始的時(shí)候,就通過(guò)OopMap這樣的一個(gè)映射表知道,在對(duì)象內(nèi)的什么偏移量上是什么類(lèi)型的數(shù)據(jù),而且特定的位置記錄下棧和寄存器中哪些位置是引用。

2.SafePoint(安全點(diǎn))

上面講到了為了快點(diǎn)進(jìn)行可達(dá)性的分析,使用了一個(gè)引用類(lèi)型的映射表,可以快速的知道對(duì)象內(nèi)或者棧和寄存器中哪些位置是引用了。

但是隨著而來(lái)的又有一個(gè)問(wèn)題,就是在方法執(zhí)行的過(guò)程中, 可能會(huì)導(dǎo)致引用關(guān)系發(fā)生變化,那么保存的OopMap就要隨著變化。如果每次引用關(guān)系發(fā)生了變化都要去修改OopMap的話(huà),這又是一件成本很高的事情。所以這里就引入了安全點(diǎn)的概念。

什么是安全點(diǎn)?OopMap的作用是為了在GC的時(shí)候,快速進(jìn)行可達(dá)性分析,所以O(shè)opMap并不需要一發(fā)生改變就去更新這個(gè)映射表。只要這個(gè)更新在GC發(fā)生之前就可以了。所以O(shè)opMap只需要在預(yù)先選定的一些位置上記錄變化的OopMap就行了。這些特定的點(diǎn)就是SafePoint(安全點(diǎn))。由此也可以知道,程序并不是在所有的位置上都可以進(jìn)行GC的,只有在達(dá)到這樣的安全點(diǎn)才能暫停下來(lái)進(jìn)行GC。

既然安全點(diǎn)決定了GC的時(shí)機(jī),那么安全點(diǎn)的選擇就至為重要了。安全點(diǎn)太少,會(huì)讓GC等待的時(shí)間太長(zhǎng),太多會(huì)浪費(fèi)性能。所以安全點(diǎn)的選擇是以程序“是否具有讓程序長(zhǎng)時(shí)間執(zhí)行的特征”為標(biāo)準(zhǔn)的(這句話(huà)是從書(shū)上看來(lái)的,不知道作者自己能不能看明白這話(huà)啥意思,反正我是看不懂),所以我們這里了解一下結(jié)果就行了。一般會(huì)在如下幾個(gè)位置選擇安全點(diǎn):

循環(huán)的末尾

方法臨返回前 / 調(diào)用方法的call指令后

可能拋異常的位置

還有一個(gè)需要考慮的問(wèn)題就是,如何讓程序在要進(jìn)行GC的時(shí)候都跑到最近的安全點(diǎn)上停頓下來(lái)。這里有兩種方案:

搶斷式中斷

搶斷式中斷就是在GC的時(shí)候,讓所有的線程都中斷,如果這些線程中發(fā)現(xiàn)中斷地方不在安全點(diǎn)上的,就恢復(fù)線程,讓他們重新跑起來(lái),直到跑到安全點(diǎn)上。(現(xiàn)在幾乎沒(méi)有虛擬機(jī)采用這種方式,原因不詳)

主動(dòng)式中斷

主動(dòng)式中斷在GC的時(shí)候,不會(huì)主動(dòng)去中斷線程,僅僅是設(shè)置一個(gè)標(biāo)志,當(dāng)程序運(yùn)行到安全點(diǎn)時(shí)就去輪訓(xùn)該位置,發(fā)現(xiàn)該位置被設(shè)置為真時(shí)就自己中斷掛起。所以輪訓(xùn)標(biāo)志的地方是和安全點(diǎn)重合的,另外創(chuàng)建對(duì)象需要分配內(nèi)存的地方也需要輪詢(xún)?cè)撐恢谩?/p>

3.安全區(qū)域

安全點(diǎn)的使用似乎解決了OopMap計(jì)算的效率的問(wèn)題,但是這里還有一個(gè)問(wèn)題。安全點(diǎn)需要程序自己跑過(guò)去,那么對(duì)于那些已經(jīng)停在路邊休息或者看風(fēng)景的程序(比如那些處在Sleep或者Blocked狀態(tài)的線程),他們可能并不會(huì)在很短的時(shí)間內(nèi)跑到安全點(diǎn)去。所以這里為了解決這個(gè)問(wèn)題,又引入了安全區(qū)域的概念。

安全區(qū)域很好理解,就是在程序的一段代碼片段中并不會(huì)導(dǎo)致引用關(guān)系發(fā)生變化,也就不用去更新OopMap表了,那么在這段代碼區(qū)域內(nèi)任何地方進(jìn)行GC都是沒(méi)有問(wèn)題的。這段區(qū)域就稱(chēng)之為安全區(qū)域。線程執(zhí)行的過(guò)程中,如果進(jìn)入到安全區(qū)域內(nèi),就會(huì)標(biāo)志自己已經(jīng)進(jìn)行到安全區(qū)域了。那么虛擬機(jī)要進(jìn)行GC的時(shí)候,發(fā)現(xiàn)該線程已經(jīng)運(yùn)行到安全區(qū)域,就不會(huì)管該線程的死活了。所以,該線程在脫離安全區(qū)域的時(shí)候,要自己檢查系統(tǒng)是否已經(jīng)完成了GC或者根節(jié)點(diǎn)枚舉(這個(gè)跟GC的算法有關(guān)系),如果完成了就繼續(xù)執(zhí)行,如果未完成,它就必須等待收到可以安全離開(kāi)安全區(qū)域的Safe Region的信號(hào)為止。

總結(jié)

以上是生活随笔為你收集整理的java安全点_关于OopMap、SafePoint(安全点)以及安全区域的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。