最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java的finalize方法解讀

 更新時間:2023年09月28日 09:14:57   作者:weixin_43831204  
這篇文章主要介紹了java的finalize方法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

我們通常用構(gòu)造器來創(chuàng)建對象,而Finalize正好相反,構(gòu)造方法執(zhí)行對象的初始化操作,finalize方法執(zhí)行對象的銷毀操作.那我們什么時候需要使用finalize方法呢,我們都知道Java里垃圾回收器可以回收對象使用的內(nèi)存空間,但是對象可能會持有很多資源比如Socket、文件句柄等,垃圾收集器無法回收這些資源,因此你需要使用finalize方法幫助GC回收這些資源,比如關(guān)閉打開的文件或者網(wǎng)元資源,刪除臨時文件等.

一個例子

Object類是所有類的父類,如果你去查看java.lang.Object類的源碼,你會發(fā)現(xiàn)里面有個finalize方法,這個方法沒有默認實現(xiàn),需要子類根據(jù)實際情況重寫這個方法,但是如果不恰當(dāng)使用finalize方法可能會造成很大的負面影響,

比如下面的例子:

public class Finalizer {
    @Override
    protected void finalize() throws Throwable {
    while (true) {
           Thread.yield();
      }
  }
public static void main(String str[]) {
  while (true) {
        for (int i = 0; i < 100000; i++) {
            Finalizer force = new Finalizer();
        }
   }
 }
}

當(dāng)我們運行上述代碼時,可以看到創(chuàng)建大量的Finalizer對象,運行一段時間后一般出現(xiàn)以下兩種結(jié)果:

  • JVM異常退出并且生成了內(nèi)存鏡像Dump
  • JVM拋出了一個異常:Out of Memory:GC OverHead limit exceeded.

不管上述兩種情況,JVM都崩潰了,那到底執(zhí)行finalize方法時發(fā)生了什么.Jvm會給每個實現(xiàn)了finalize方法的實例創(chuàng)建一個監(jiān)聽,這個稱為Finalizer,每次調(diào)用對象的finalize方法時,JVM會創(chuàng)建一個 java.lang.ref.Finalizer 對象,這個Finalizer對象會持有這個對象的引用,由于這些對象被Finilizer對象引用了,當(dāng)對象數(shù)量較多時,就會導(dǎo)致Eden區(qū)空間滿了,經(jīng)歷多次youngGC后可能對象就進入到老年代了. java.lang.ref.Finalizer 類繼承自 java.lang.ref.FinalReference ,也是Refence的一種,因此Finalizer類里也有一個引用隊列,這個引用隊列是JVM和垃圾回收器打交道的唯一途徑,當(dāng)垃圾回收器需要回收該對象時,會把該對象放到引用隊列中,這樣java.lang.ref.Finalizer類就可以從隊列中取出該對象,執(zhí)行對象的finalize方法,并清除和該對象的引用關(guān)系.需要注意的是只有finalize方法實現(xiàn)不為空時JVM才會執(zhí)行上述操作,JVM在類的加載過程中會標(biāo)記該類是否為finalize類.

GC怎么處理這些對象呢

當(dāng)老年代空間達到了OldGC條件時,JVM執(zhí)行一次OldGC,當(dāng)OldGC執(zhí)行后JVM檢測到這些對象只被Finalizer對象引用,這些對象會被標(biāo)記成要被清除的對象,GC會把所有的Finalizer對象放入到一個引用隊列: java.lang.ref.Finalizer.ReferenceQueue .

Finalizer對象怎么被清理的呢

JVM默認會創(chuàng)建一個finalizer線程來處理Finalizer對象,如果你去抓取線程堆棧的話可以看到這個線程的堆棧,

如下所示:

"Finalizer" daemon prio=10 tid=0x0962d000 nid=0x4836 runnable [0xafaa8000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.Thread.yield(Native Method)
        at finalizer.finalize(finalizer.java:5)
        at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
        at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:83)
        at java.lang.ref.Finalizer.access$100(Finalizer.java:14)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:160)

這個線程唯一的職責(zé)就是不斷的從 java.lang.ref.Finalizer.ReferenceQueue 隊列中取對象,當(dāng)一個對象進入到隊列中,finalizer線程就執(zhí)行對象的finalize方法并且把對象從隊列中刪除,因此在下一次GC周期中可以看到這個對象和Finalizer對象都被清除了.

大部分場景finalizer線程清理finalizer隊列是比較快的,但是一旦你在finalize方法里執(zhí)行一些耗時的操作,可能導(dǎo)致內(nèi)存無法及時釋放進而導(dǎo)致內(nèi)存溢出的錯誤,在實際場景還是推薦盡量少用finalize方法.

簡單粗暴,一個死循環(huán)去隊列里面拿出Finalizer對象,并執(zhí)行finalize方法,再置空為null,可供垃圾回收

實戰(zhàn)案例

public class Finalizer {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize");
    }
    public static void main(String str[]) throws IOException {
            for (int i = 0; i < 10000; i++) {
                Finalizer force = new Finalizer();
            }
            //讓線程阻塞住,方便分析內(nèi)存使用情況
        System.in.read();
    }
}

執(zhí)行main方法后使用jmap命令查看內(nèi)存使用情況,可以看到 java.lang.ref.Finalizer 和Finalizer的實例都創(chuàng)建了10000個:

$ jmap -histo 8700|head -n 10
 num     #instances         #bytes  class name
----------------------------------------------
   1:           646        3398408  [I
   2:          1851        1511144  [B
   3:          6081         808864  [C
   4:         10175         407000  java.lang.ref.Finalizer
   5:         10000         160000  Finalizer
   6:          4328         103872  java.lang.String
   7:           601          64208  java.lang.Class
   8:           683          40952  [Ljava.lang.Object;
   9:           785          31400  java.util.TreeMap$Entry
  10:           248          14144  [Ljava.lang.String;

接下來使用jmap -histo:live 8700|head -n 10命令強制觸發(fā)一次GC,結(jié)果和前面的分析一致,F(xiàn)inalizer對象都放到引用隊列中,并依次調(diào)用了對象的finalize方法,內(nèi)存中java.lang.ref.Finalizer和Finalizer對象依然存在,不過這一java.lang.ref.Finalizer

不再引用Finalizer對象,下一次GC周期時兩者都屬于垃圾對象:

$ jmap -histo:live 8700|head -n 10
 num     #instances         #bytes  class name
----------------------------------------------
   1:         10175         407000  java.lang.ref.Finalizer
   2:          3043         372608  [C
   3:           605         273624  [B
   4:         10000         160000  Finalizer
   5:          2883          69192  java.lang.String
   6:           601          64208  java.lang.Class
   7:           631          37008  [Ljava.lang.Object;

再觸發(fā)一次jmap -histo:live 8700|head -n 10,可以看到兩者都被回收了:

$ jmap -histo:live 8700|head -n 10
 num     #instances         #bytes  class name
----------------------------------------------
   1:          3059         373224  [C
   2:           498         138064  [B
   3:          2899          69576  java.lang.String
   4:           602          64312  java.lang.Class
   5:           631          37008  [Ljava.lang.Object;
   6:           785          31400  java.util.TreeMap$Entry
   7:           227          11256  [Ljava.lang.String;

我們來總結(jié)一下

finalize對象至少經(jīng)歷兩次GC才能被回收,因為只有在FinalizerThread執(zhí)行完了finalize對象的finalize方法的情況下才有可能被下次GC回收,而有可能期間已經(jīng)經(jīng)歷過多次GC了,但是一直還沒執(zhí)行finalize對象的finalize方法;

CPU資源不足的場景FinalizerThread線程可能因為優(yōu)先級較低而一直沒有執(zhí)行對象的finalize方法,可能導(dǎo)致大部分對象進入到老年代,進而觸發(fā)老年代GC,設(shè)置觸發(fā)Full GC.

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

相關(guān)文章

  • Java智能體AI?Agent開發(fā)中常見誤區(qū)與避坑指南

    Java智能體AI?Agent開發(fā)中常見誤區(qū)與避坑指南

    隨著AI?Agent技術(shù)的興起,Java開發(fā)者也紛紛投身智能體開發(fā),本文將深入剖析3個最常見的誤區(qū),幫助你在Java智能體學(xué)習(xí)路上少走彎路,有需要的小伙伴快跟隨小編一起學(xué)習(xí)起來吧
    2026-03-03
  • Hibernatede 一對多映射配置方法(分享)

    Hibernatede 一對多映射配置方法(分享)

    下面小編就為大家?guī)硪黄狧ibernatede 一對多映射配置方法(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • Java基于HttpClient實現(xiàn)RPC的示例

    Java基于HttpClient實現(xiàn)RPC的示例

    HttpClient可以實現(xiàn)使用Java代碼完成標(biāo)準(zhǔn)HTTP請求及響應(yīng)。本文主要介紹了Java基于HttpClient實現(xiàn)RPC,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Java中的Null到底是什么

    Java中的Null到底是什么

    null是沒有地址,""是有地址但是里面的內(nèi)容是空的,好比做飯 null說明連鍋都沒有 而""則是有鍋沒米,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,下面我們來詳細學(xué)習(xí)一下它吧
    2019-06-06
  • SpringCloud實戰(zhàn)之Zuul網(wǎng)關(guān)服務(wù)

    SpringCloud實戰(zhàn)之Zuul網(wǎng)關(guān)服務(wù)

    服務(wù)網(wǎng)關(guān)是分布式架構(gòu)中不可缺少的組成部分,是外部網(wǎng)絡(luò)和內(nèi)部服務(wù)之間的屏障。這篇文章主要介紹了SpringCloud實戰(zhàn)之Zuul網(wǎng)關(guān)服務(wù)。一起跟隨小編過來看看吧
    2018-05-05
  • SpringBoot實現(xiàn)Word轉(zhuǎn)PDF和TXT的實踐分享

    SpringBoot實現(xiàn)Word轉(zhuǎn)PDF和TXT的實踐分享

    研發(fā)工作中難免會遇到一些奇奇怪怪的需求,就比如最近,客戶提了個新需求:上傳一個WORD文檔,要求通過系統(tǒng)把該文檔轉(zhuǎn)換成PDF和TXT,所以本文給大家分享了SpringBoot實現(xiàn)Word轉(zhuǎn)PDF和TXT的實踐,感興趣的朋友可以參考下
    2024-08-08
  • Java spring的三種注入方式詳解流程

    Java spring的三種注入方式詳解流程

    Spring框架由Rod Johnson開發(fā),2004年發(fā)布了Spring框架的第一版。Spring是一個從實際開發(fā)中抽取出來的框架,因此它完成了大量開發(fā)中的通用步驟,留給開發(fā)者的僅僅是與特定應(yīng)用相關(guān)的部分,從而大大提高了企業(yè)應(yīng)用的開發(fā)效率
    2021-10-10
  • XSS攻擊以及java應(yīng)對xss攻擊的解決方案

    XSS攻擊以及java應(yīng)對xss攻擊的解決方案

    XSS是跨站腳本攻擊Cross Site Scripting的縮寫,為了和層疊樣式表CSS加以區(qū)分,因此將跨站腳本攻擊縮寫為XSS,這篇文章主要給大家介紹了關(guān)于XSS攻擊以及java應(yīng)對xss攻擊的解決方案,需要的朋友可以參考下
    2024-02-02
  • 在Java項目中實現(xiàn)CI/CD持續(xù)集成與持續(xù)部署

    在Java項目中實現(xiàn)CI/CD持續(xù)集成與持續(xù)部署

    這篇文章主要為大家介紹了在Java項目中實現(xiàn)CI/CD持續(xù)集成與持續(xù)部署詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • SpringBoot實現(xiàn)文件上傳與下載功能的示例代碼

    SpringBoot實現(xiàn)文件上傳與下載功能的示例代碼

    文件上傳與下載是Web應(yīng)用開發(fā)中常用的功能之一。接下來我們將討論如何在Spring?Boot的Web應(yīng)用開發(fā)中,如何實現(xiàn)文件的上傳與下載,感興趣的可以了解一下
    2022-06-06

最新評論

镇雄县| 兰坪| 巫溪县| 剑河县| 宕昌县| 江川县| 顺义区| 深水埗区| 樟树市| 教育| 福建省| 锦州市| 鹤峰县| 衡阳市| 蓬溪县| 莱州市| 忻州市| 陆河县| 黑河市| 墨玉县| 无锡市| 札达县| 额尔古纳市| 盐津县| 永胜县| 财经| 清苑县| 江山市| 昂仁县| 石楼县| 平邑县| 北碚区| 彭阳县| 泉州市| 漳平市| 兰西县| 衡水市| 达拉特旗| 遂平县| 台州市| 阿克苏市|