亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring bean不被GC的真正原因及分析

 更新時(shí)間:2024年04月29日 10:06:35   作者:Bryant5051  
這篇文章主要介紹了Spring bean不被GC的真正原因及分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

概述

自從開(kāi)始接觸 Spring 之后,一直以來(lái)都在思考一個(gè)問(wèn)題,在 Spring 應(yīng)用的運(yùn)行過(guò)程中,為什么這些 bean 不會(huì)被回收?

今天深入探究了這個(gè)問(wèn)題之后,才有了答案。

思考點(diǎn)

大家都知道,一個(gè) bean 會(huì)不會(huì)被回收,取決于對(duì)象存活判定算法

JVM 底層中使用的是可達(dá)性分析算法,拋開(kāi) HotSpot 的實(shí)現(xiàn)細(xì)節(jié)不談,那么一個(gè)對(duì)象被判定為死亡,應(yīng)該與 GC Root 不存在可達(dá)的引用路徑。

所以,Spring 的 bean 肯定是與 GC Root 存在可達(dá)的引用路徑,才不會(huì)被回收掉

Java 語(yǔ)言對(duì)于 GC Root 的定義中,以下幾種對(duì)象可以作為 GC Root

  • 虛擬機(jī)棧的棧幀中的本地變量表中,引用類型對(duì)象所指向的堆中的對(duì)象
  • 處于運(yùn)行中狀態(tài)(RUNNABLE,BLOCKED,WAITING,TIMED_WAITING)的線程對(duì)象
  • JDK 自帶的類加載器對(duì)象
  • 本地方法所引用的對(duì)象
  • JVM 持有的對(duì)象,例如基本類型的 Class 對(duì)象,NullPointerException 等常用異常對(duì)象
  • 被 synchronized 關(guān)鍵字修飾的對(duì)象

一般來(lái)說(shuō),只要是符合上面這幾種規(guī)則的對(duì)象,或者能由上面的規(guī)則推導(dǎo)出存在引用的對(duì)象,都可以作為 GC Root。

那么 SpringbeanGC Root 是哪一種呢?或者說(shuō),找到了 SpringbeanGC Root,就找到了問(wèn)題的答案。

動(dòng)手尋找答案

首先新建一個(gè) SpringBoot 應(yīng)用,里面定義了兩個(gè) bean 以及一個(gè)啟動(dòng)類,包結(jié)構(gòu)如下:

然后點(diǎn)擊運(yùn)行啟動(dòng)類,啟動(dòng)完成之后,打開(kāi) jvisualVM ,找到對(duì)應(yīng)的應(yīng)用,然后點(diǎn)擊生成當(dāng)前dump

然后打開(kāi)后選擇類,輸入 Hello 過(guò)濾類名,找到 HelloWorldService,點(diǎn)擊在實(shí)例視圖中顯示,發(fā)現(xiàn)只有一個(gè)實(shí)例存在,這符合我們的預(yù)期。

最后右鍵點(diǎn)擊這個(gè)實(shí)例,選擇顯示最近的垃圾回收根節(jié)點(diǎn),可以觀察到如下的引用路徑:

可以看到,DefaultListableBeanFactoryAnnotationConfigServletWebServerApplicationContext 都是我們比較熟悉的 bean 容器,對(duì)應(yīng)的往下找發(fā)現(xiàn)有 ConcurrentHashMap$Node 引用。

我們都知道在 Spring 中,正是這兩個(gè)容器(準(zhǔn)確地說(shuō)是 DefaultListableBeanFactory)中使用 ConcurrentHashMap 存放了實(shí)例化好的 bean。 這都是非常符合我們預(yù)期的。

但是在 AbstractApplicationContext 再往上找后,發(fā)現(xiàn)有個(gè)叫 ApplicationShutdownHooks 的東西。意思就是說(shuō),我們的容器,最終與這個(gè) ApplicationShutdownHooks 的東西扯上了引用關(guān)系。接

著我們翻閱 Spring 源碼進(jìn)行求證:

發(fā)現(xiàn)在 AbstractApplicationContextregisterShutdownHook 方法中調(diào)用了這一行代碼,而 registerShutdownHook 方法正是在 Spring 容器初始化時(shí)要調(diào)用的方法:

這說(shuō)明在 Spring 容器初始化時(shí),調(diào)用的這個(gè)方法,然后在繼續(xù)往里跟蹤這個(gè)方法:

最后我們可以發(fā)現(xiàn),AbstractApplicationContext 中的 Thread shutdownHook 變量,最終被放在了 ApplicationShutdownHooks 的這個(gè) map 里面,而這個(gè) map 恰好就是一個(gè)靜態(tài)變量。

結(jié)論

所以,Springbean 沒(méi)有被回收,正是因?yàn)樵?AbstractApplicatuonContextregisterShutdownHook 方法中,與 ApplicationShutdownHooks 中的一個(gè)靜態(tài)變量建立了可達(dá)的引用路徑。

題外話

那么為什么類的靜態(tài)變量可以作為 GC Root 呢?抱著嚴(yán)謹(jǐn)?shù)男膽B(tài),我們繼續(xù)往下求證:

類的靜態(tài)變量屬于類對(duì)象,類對(duì)象由類加載器進(jìn)行加載,而類加載器是 GC Root,那么類加載器是不是與被加載的類對(duì)象存在引用關(guān)系呢?

翻閱 ClassLoader 類,赫然看到這一段代碼:

public abstract class ClassLoader {
    // The classes loaded by this class loader. The only purpose of this table
    // is to keep the classes from being GC'ed until the loader is GC'ed.
    private final Vector<Class<?>> classes = new Vector<>();
}

注釋一目了然,好家伙!原來(lái)類加載器把所有的已加載的類對(duì)象都保存在這個(gè)容器里面,怪不得類對(duì)象和類靜態(tài)變量也屬于 GC Root

最后

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java語(yǔ)言描述Redis分布式鎖的正確實(shí)現(xiàn)方式

    java語(yǔ)言描述Redis分布式鎖的正確實(shí)現(xiàn)方式

    這篇文章主要介紹了java語(yǔ)言描述Redis分布式鎖的正確實(shí)現(xiàn)方式,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • 這一次搞懂Spring代理創(chuàng)建及AOP鏈?zhǔn)秸{(diào)用過(guò)程操作

    這一次搞懂Spring代理創(chuàng)建及AOP鏈?zhǔn)秸{(diào)用過(guò)程操作

    這篇文章主要介紹了這一次搞懂Spring代理創(chuàng)建及AOP鏈?zhǔn)秸{(diào)用過(guò)程操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • IDEA?+?Maven環(huán)境下的SSM框架整合及搭建過(guò)程

    IDEA?+?Maven環(huán)境下的SSM框架整合及搭建過(guò)程

    這篇文章主要介紹了IDEA?+?Maven環(huán)境下的SSM框架整合及搭建過(guò)程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • Java中關(guān)于優(yōu)先隊(duì)列PriorityQueue的使用及相關(guān)方法

    Java中關(guān)于優(yōu)先隊(duì)列PriorityQueue的使用及相關(guān)方法

    這篇文章主要介紹了Java中關(guān)于優(yōu)先隊(duì)列PriorityQueue的使用及相關(guān)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 基于springBoot配置文件properties和yml中數(shù)組的寫法

    基于springBoot配置文件properties和yml中數(shù)組的寫法

    這篇文章主要介紹了springBoot配置文件properties和yml中數(shù)組的寫法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java Mybatis一級(jí)緩存和二級(jí)緩存

    Java Mybatis一級(jí)緩存和二級(jí)緩存

    緩存是內(nèi)存當(dāng)中一塊存儲(chǔ)數(shù)據(jù)的區(qū)域,目的是提高查詢效率,降低服務(wù)器和數(shù)據(jù)庫(kù)的壓力,這篇文章主要介紹了Mybatis一級(jí)緩存和二級(jí)緩存,感興趣的同學(xué)可以參考閱讀本文
    2023-04-04
  • 2020最新版SSM框架整合教程

    2020最新版SSM框架整合教程

    這篇文章主要介紹了2020最新版SSM框架整合教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 多方面解讀Java中的volatile關(guān)鍵字

    多方面解讀Java中的volatile關(guān)鍵字

    這篇文章主要介紹了多方面解讀Java中的volatile關(guān)鍵字,它的作用是強(qiáng)制對(duì)被修飾的變量的寫操作立即刷新到主存中,并強(qiáng)制對(duì)該變量的讀操作從主存中讀取最新的值,而不是使用緩存中的值,需要的朋友可以參考下
    2023-05-05
  • Java實(shí)現(xiàn)線程插隊(duì)的示例代碼

    Java實(shí)現(xiàn)線程插隊(duì)的示例代碼

    在編寫多線程的業(yè)務(wù)時(shí),會(huì)遇到讓一個(gè)線程優(yōu)先于其他線程運(yùn)行的情況,除了可以設(shè)置線程的優(yōu)先級(jí)高于其他線程,還有更直接的方式:線程插隊(duì)。本文將用Java實(shí)現(xiàn)線程插隊(duì),需要的可以參考一下
    2022-08-08
  • Java獲取文件的路徑及常見(jiàn)問(wèn)題解決方案

    Java獲取文件的路徑及常見(jiàn)問(wèn)題解決方案

    這篇文章主要介紹了Java獲取文件的路徑及常見(jiàn)問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論