pos機(jī)面試技巧,聊聊 GC 機(jī)制

 新聞資訊2  |   2023-06-23 17:49  |  投稿人:pos機(jī)之家

網(wǎng)上有很多關(guān)于pos機(jī)面試技巧,聊聊 GC 機(jī)制的知識(shí),也有很多人為大家解答關(guān)于pos機(jī)面試技巧的問(wèn)題,今天pos機(jī)之家(m.dsth100338.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來(lái)看下吧!

本文目錄一覽:

1、pos機(jī)面試技巧

pos機(jī)面試技巧

前言

GC 中文直譯垃圾回收,是一種回收內(nèi)存空間避免內(nèi)存泄漏的機(jī)制。當(dāng) JVM 內(nèi)存緊張,通過(guò)執(zhí)行 GC 有效回收內(nèi)存,轉(zhuǎn)而分配給新對(duì)象從而實(shí)現(xiàn)內(nèi)存的再利用。 JVM GC 機(jī)制雖然無(wú)需開(kāi)發(fā)主動(dòng)參與,減輕不少工作量,但是某些情況下,自動(dòng) GC 將會(huì)導(dǎo)致系統(tǒng)性能下降,響應(yīng)變慢,所以這就需要我們提前了解掌握 GC 機(jī)制。當(dāng)面對(duì)這種情況時(shí),才能從容不迫的解決問(wèn)題。另外 GC 機(jī)制也是 Java 面試高頻考題,了解掌握 GC 是一項(xiàng)必備技能。

學(xué)習(xí) GC ,首先我們解決三個(gè)問(wèn)題:

什么是垃圾在哪里回收垃圾怎么回收垃圾什么是垃圾

我們先來(lái)看一段簡(jiǎn)單的代碼。

上面代碼通過(guò)將字符串對(duì)象轉(zhuǎn)化成字節(jié)數(shù)組,然后寫(xiě)入本地文件。方法一旦開(kāi)始執(zhí)行,就將會(huì)在分配一定內(nèi)存給新建的對(duì)象,然后將引用告訴了str, bytes 變量。等到方法執(zhí)行完畢,方法內(nèi)部局部變量緊接將就會(huì)被銷(xiāo)毀。但是這樣僅僅銷(xiāo)毀了局部變量,卻沒(méi)有帶走內(nèi)存上這些實(shí)際的對(duì)象。這類(lèi)不再起作用,沒(méi)有被引用的對(duì)象,將其歸類(lèi)為垃圾。

在偌大的內(nèi)存上存活著無(wú)數(shù)對(duì)象,GC 之前需要準(zhǔn)確將這些對(duì)象標(biāo)記出來(lái),分為存活對(duì)象與垃圾對(duì)象。這個(gè)過(guò)程一旦少標(biāo)記,那就只能等待下次 GC標(biāo)記,再回收,這樣將會(huì)影響 GC 效率。另外決不能錯(cuò)標(biāo)記,將正常存活對(duì)象標(biāo)記為垃圾。一旦回收正常存活的對(duì)象,可能就會(huì)引起程序各種崩潰。

目前有兩種算法可以用來(lái)標(biāo)記:

引用計(jì)數(shù)法可達(dá)性分析法引用計(jì)數(shù)法

引用計(jì)數(shù)法通過(guò)在對(duì)象頭分配一個(gè)字段,用來(lái)存儲(chǔ)該對(duì)象引用計(jì)數(shù)。一旦該對(duì)象被其他對(duì)象引用,計(jì)數(shù)加 1。如果這個(gè)引用失效,計(jì)數(shù)減 1。當(dāng)引用計(jì)數(shù)值為 0 時(shí),代表這個(gè)對(duì)象已不再被引用,可以被回收。

如上圖所示,當(dāng) str 引用堆中對(duì)象時(shí),計(jì)數(shù)值增加為 1。當(dāng) str 變?yōu)?null 時(shí),既不再引用該對(duì)象,計(jì)數(shù)值減 1。此時(shí)該對(duì)象就可以被 GC 回收。

引用計(jì)數(shù)法只需要判斷計(jì)數(shù)值,所以實(shí)現(xiàn)比較簡(jiǎn)單,這個(gè)過(guò)程也比較高效。但是存在一個(gè)很?chē)?yán)重的問(wèn)題,無(wú)法解決對(duì)象循環(huán)引用問(wèn)題。

從上圖可以看到, a,b 不再引用堆中對(duì)象,導(dǎo)致計(jì)數(shù)減一。此時(shí)兩個(gè)對(duì)象內(nèi)部還存在互相引用,計(jì)數(shù)值不為 0,此時(shí) GC 沒(méi)辦法回收該對(duì)象。

可達(dá)性分析法

這個(gè)算法首先需要按照規(guī)則查找當(dāng)前活躍的引用,將其稱為 GC Roots。接著將 GC Roots 作為根節(jié)點(diǎn)出發(fā),遍歷對(duì)象引用關(guān)系圖,將可以遍歷(可達(dá))的對(duì)象標(biāo)記為存活,其余對(duì)象當(dāng)做無(wú)用對(duì)象。

注意這里是是引用,而不是對(duì)象。

從上圖可以看到,綠色對(duì)象雖然存在循環(huán)引用,但是由于這些對(duì)象不能被 GC Roots 遍歷到,所以將會(huì)被回收。

可以被當(dāng)做GC Roots 活躍引用包括但不限于以下引用:

方法中局部變量靜態(tài)變量,常量JNI handles….在哪里回收垃圾

還記得剛開(kāi)始接觸 Java 時(shí),只知道堆棧,對(duì)象實(shí)例分配在堆中,方法中局部變量位于棧中。實(shí)際上 JVM 內(nèi)存區(qū)域劃分更加細(xì)致,分為:

堆方法區(qū)虛擬機(jī)棧本地方法棧程序計(jì)數(shù)器

如圖所示,我們將內(nèi)存劃分為線程私有與線程共享的區(qū)域。方法區(qū)與堆都是線程共享的區(qū)域,這兩部分占用 JVM 大部分內(nèi)存,剩下三個(gè)小弟將會(huì)跟線程綁定,隨著線程消亡,自動(dòng)將會(huì)被 JVM 回收。

堆應(yīng)該是大家最熟悉的一塊區(qū)域,幾乎所有對(duì)象實(shí)例都將會(huì)在此出生,通常也是虛擬機(jī)上占用內(nèi)存最大一塊區(qū)域,簡(jiǎn)直就是 JVM 內(nèi)存中的大哥大。堆內(nèi)存內(nèi)部也不是簡(jiǎn)簡(jiǎn)單單一塊而已,目前將會(huì)根據(jù)分代算法,將堆分代,不同對(duì)象位于不同區(qū)域。這一點(diǎn)我們下文再詳細(xì)了解。

方法區(qū)

方法區(qū)將會(huì)保存已被虛擬上加載的類(lèi)信息、常量,靜態(tài)變量,字節(jié)碼等信息,堆上的對(duì)象正式通過(guò)方法區(qū)這些信息,才能正確創(chuàng)建出來(lái)。

虛擬機(jī)棧棧由一系列棧幀組成,每個(gè)棧幀其實(shí)代表一個(gè)方法,棧幀中將會(huì)保存一個(gè)方法的局部變量表,方法出入口信息,操作棧等。每當(dāng)調(diào)用一個(gè)方法,就將會(huì)把這個(gè)棧幀壓入棧中,執(zhí)行結(jié)束,出棧。

本地方法棧與虛擬機(jī)棧比較類(lèi)似,最大區(qū)別在于,虛擬機(jī)棧執(zhí)行的 Java 方法,而本地方法棧將會(huì)用來(lái)執(zhí)行 Native 方法服務(wù)。下面方法就會(huì)在本地方法棧中執(zhí)行。

public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

程序計(jì)數(shù)器

程序計(jì)算器可以說(shuō)是這幾塊區(qū)域占用最小的一部分,但是功能卻十分重要。Java 源代碼通過(guò)編譯變成字節(jié)碼,然后被 JVM 載入運(yùn)行之后,將會(huì)變成一條條指令,而程序計(jì)數(shù)器的工作就是告訴當(dāng)前線程下一條需要執(zhí)行指令。這樣即使發(fā)生了線程切換,等待恢復(fù)的時(shí)候,當(dāng)前線程依然知道接下去要執(zhí)行的指令。

怎么回收

目前主流 GC 算法主要分為三種:

標(biāo)記-清除算法復(fù)制算法標(biāo)記-整理算法標(biāo)記-清除算法

這是一個(gè)最為基礎(chǔ)也是最容易實(shí)現(xiàn)的算法,主要實(shí)現(xiàn)步驟分為兩步:標(biāo)記,清除。

標(biāo)記:通過(guò)上述 GC Roots 標(biāo)記出可達(dá)對(duì)象。清除:清理未標(biāo)記對(duì)象。

ps:這個(gè)圖著實(shí)難畫(huà)啊。。。。

可以看到經(jīng)過(guò)這個(gè)算法回收之后,雖然堆空間被清理出來(lái),但是也產(chǎn)生很多空間碎片。這就會(huì)導(dǎo)致一個(gè)新對(duì)象根據(jù)堆剩余容量計(jì)算,看起來(lái)是可以分配,但是實(shí)際分配過(guò)程,由于沒(méi)有連續(xù)內(nèi)存,導(dǎo)致虛擬機(jī)感知到內(nèi)存不足,又不得不提前再次觸發(fā) GC。

可能這里你就會(huì)有疑惑,為什么對(duì)象需要分配一塊連續(xù)的內(nèi)存?

這里引用一下 R 神 @RednaxelaFX 答案。

另外這個(gè)算法還有一個(gè)不足:標(biāo)記與清除效率比較低。這就竟會(huì)導(dǎo)致 GC 占用時(shí)間過(guò)長(zhǎng),影響正常程序使用。

復(fù)制算法

為了解決上述效率問(wèn)題,誕生復(fù)制算法。這個(gè)算法將可用內(nèi)存分為兩塊,每次只使用其中一塊,當(dāng)這一塊內(nèi)存使用完畢,觸發(fā) GC ,將會(huì)把存活的對(duì)象依次復(fù)制到另外一塊上,然后再把已使用過(guò)的內(nèi)存一次性清理。

這個(gè)算法每次只需要操作一半內(nèi)存,GC 回收之后也不存在任何空間碎片,新對(duì)象內(nèi)存分配時(shí)只需要移動(dòng)堆頂指針,按順序分配內(nèi)存即可,實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效。但是這個(gè)算法閑置一半內(nèi)存空間,空間利用效率不高。

PS:復(fù)制算法以空間換時(shí)間,兩者不可兼得

另外對(duì)象存活率也會(huì)影響復(fù)制算法效率。如果對(duì)象大部分都是朝生夕死,只需要移動(dòng)少量存活對(duì)象,就能騰出大部分空間。反而如果對(duì)象存活率高,這就需要進(jìn)行較多的復(fù)制操作,回收之后也并沒(méi)有多余內(nèi)存,這就可能導(dǎo)致頻繁觸發(fā) GC。

針對(duì)這種存活時(shí)間長(zhǎng)的對(duì)象,就需要使用標(biāo)記-整理算法。

標(biāo)記-整理算法

標(biāo)記-整理算法可以說(shuō)是標(biāo)記-清除算法的改進(jìn)版,改進(jìn)了清除導(dǎo)致的空間碎片問(wèn)題。這個(gè)算法分為兩步:

標(biāo)記:也是通過(guò) GC Roots 標(biāo)記存活對(duì)象。整理:將存活對(duì)象往一端移動(dòng),按照內(nèi)存地址一次排序,然后將末端邊界之外內(nèi)存直接清理。

雖然標(biāo)記-整理算法解決了標(biāo)記-清除算法空間碎片問(wèn)題,也完整利用整個(gè)內(nèi)存空間,但是這個(gè)算法問(wèn)題效率并不高。相較于標(biāo)記-清除算法,標(biāo)記-整理算法多增加整理這一步,所以該算法效率還低于標(biāo)記-清除算法。

分代收集算法

從上面三種 GC 算法可以看到,并沒(méi)有一種空間與時(shí)間效率都是比較完美的算法,所以只能做的是綜合利用各種算法特點(diǎn)將其作用到不用的內(nèi)存區(qū)域。

目前商業(yè)虛擬機(jī)根據(jù)對(duì)象存活周期不同劃分內(nèi)存區(qū)域,一般分為新生代,老年代。新對(duì)象一般情況都會(huì)優(yōu)先分配在新生代,新生代對(duì)象若存活時(shí)間大于一定閾值之后,將會(huì)移到至老年代。新生代的對(duì)象都是短命鬼,老年代的對(duì)象都是長(zhǎng)壽先生。

新生代每次 GC 之后都可以回收大批量對(duì)象,所以比較適合復(fù)制算法,只需要付出少量復(fù)制存活對(duì)象的成本。這里內(nèi)存劃分并沒(méi)有按照 1:1 劃分,默認(rèn)將會(huì)按照 8:1:1 劃分成 Eden 與兩塊 Survivor空間。每次使用 Eden 與一塊Survivor空間,這樣我們只是閑置 10% 內(nèi)存空間。不過(guò)我們每次回收并不能保證存活對(duì)象小于 10%,在這種情況下就需要依靠老年代的內(nèi)存分配擔(dān)保。當(dāng)Survivor空間并不能保存剩余存活對(duì)象,就將這些對(duì)象通過(guò)分配擔(dān)保進(jìn)制移動(dòng)至老年代。

老年代中對(duì)象存活率將會(huì)特別高,且沒(méi)有額外空間進(jìn)行分配擔(dān)保,所以并不適合復(fù)制算法,所以需要使用標(biāo)記-清除或標(biāo)記-整理算法。

隨便聊聊

最近又到一年一次大考的時(shí)候,不得不又拿起周志明『深入 Java 虛擬機(jī)』重新學(xué)習(xí)。還記得第一次翻看這本書(shū)的時(shí)候,大半內(nèi)容看不懂,看完也很快就忘了。然后過(guò)了一段時(shí)間,又重新拿起此書(shū),這次比上次好,也已經(jīng)能看小大半了。最近跟一些小伙伴聊天,發(fā)現(xiàn)他們都是看這本書(shū)學(xué)習(xí) JVM ,不得不說(shuō)這本書(shū)真是一本神書(shū)。最近『深入 Java 虛擬機(jī)』第三版即將上架開(kāi)售,有需要的小伙伴可以考慮入手了。

好了 ,GC 機(jī)制就就總結(jié)到這里,下一篇我們來(lái)聊聊 JVM 常用 GC 回收器。

幫助鏈接

GC Roots Java虛擬機(jī)詳解04—-GC算法和種類(lèi) 深入 Java 虛擬機(jī)

以上就是關(guān)于pos機(jī)面試技巧,聊聊 GC 機(jī)制的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于pos機(jī)面試技巧的知識(shí),希望能夠幫助到大家!

轉(zhuǎn)發(fā)請(qǐng)帶上網(wǎng)址:http://m.dsth100338.com/newsone/72451.html

你可能會(huì)喜歡:

版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 babsan@163.com 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。