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

簡單理解Java的垃圾回收機制與finalize方法的作用

 更新時間:2015年11月12日 15:58:21   作者:邊緣元素  
這篇文章主要介紹了簡單理解Java的垃圾回收機制與finalize方法的作用,著重講解了Java的GC銷毀對象的過程,需要的朋友可以參考下

垃圾回收器要回收對象的時候,首先要調(diào)用這個類的finalize方法(你可以 寫程序驗證這個結論),一般的純Java編寫的Class不需要重新覆蓋這個方法,因為Object已經(jīng)實現(xiàn)了一個默認的,除非我們要實現(xiàn)特殊的功能(這 里面涉及到很多東西,比如對象空間樹等內(nèi)容)。
不過用Java以外的代碼編寫的Class(比如JNI,C++的new方法分配的內(nèi)存),垃圾回收器并不能對這些部分進行正確的回收,這時就需要我們覆蓋默認的方法來實現(xiàn)對這部分內(nèi)存的正確釋放和回收(比如C++需要delete)。
總之,finalize相當于析構函數(shù),他是垃圾回收器回收一個對象的時候第一個要調(diào)用的方法。不過由于Java的垃圾回收機制能自動為我們做這些事情,所以我們在一般情況下是不需要自己來手工釋放的。

有時當撤消一個對象時,需要完成一些操作。例如,如果一個對象正在處理的是非Java 資源,如文件句柄或window 字符字體,這時你要確認在一個對象被撤消以前要保證這些資源被釋放。為處理這樣的狀況,Java 提供了被稱為收尾(finalization )的機制。使用該機制你可以定義一些特殊的操作,這些操作在一個對象將要被垃圾回收程序釋放時執(zhí)行。
要給一個類增加收尾(finalizer ),你只要定義finalize ( ) 方法即可。Java 回收該類的一個對象時,就會調(diào)用這個方法。在finalize ( )方法中,你要指定在一個對象被撤消前必須執(zhí)行的操作。垃圾回收周期性地運行,檢查對象不再被運行狀態(tài)引用或間接地通過其他對象引用。就在對象被釋放之 前,Java 運行系統(tǒng)調(diào)用該對象的finalize( ) 方法。

  finalize()方法的通用格式如下:

  protected void finalize( )
{
// finalization code here
}

  其中,關鍵字protected是防止在該類之外定義的代碼訪問finalize()標識符。該標識符和其他標識符將在第7章中解釋。

  理解finalize( ) 正好在垃圾回收以前被調(diào)用非常重要。例如當一個對象超出了它的作用域時,finalize( ) 并不被調(diào)用。這意味著你不可能知道何時——甚至是否——finalize( ) 被調(diào)用。因此,你的程序應該提供其他的方法來釋放由對象使用的系統(tǒng)資源,而不能依靠finalize( ) 來完成程序的正常操作。

  注意:如果你熟悉C++,那你知道C++允許你為一個類定義一個撤消函數(shù)(destructor ),它在對象正好出作用域之前被調(diào)用。Java不支持這個想法也不提供撤消函數(shù)。finalize() 方法只和撤消函數(shù)的功能接近。當你對Java 有豐富經(jīng)驗時,你將看到因為Java使用垃圾回收子系統(tǒng),幾乎沒有必要使用撤消函數(shù)。


finalize的工作原理應該是這樣的:一旦垃圾收集器準備好釋放對象占用的存儲空間,它首先調(diào)用finalize(),而且只有在下一次垃圾收集過程中,才會真正回收對象的內(nèi)存.所以如果使用finalize(),就可以在垃圾收集期間進行一些重要的清除或清掃工作.

finalize()在什么時候被調(diào)用?
有三種情況

  1. 所有對象被Garbage Collection時自動調(diào)用,比如運行System.gc()的時候.
  2. 程序退出時為每個對象調(diào)用一次finalize方法。
  3. 顯式的調(diào)用finalize方法

除此以外,正常情況下,當某個對象被系統(tǒng)收集為無用信息的時候,finalize()將被自動調(diào)用,但是jvm不保證finalize()一定被調(diào)用,也就是說,finalize()的調(diào)用是不確定的,這也就是為什么sun不提倡使用finalize()的原因

有時當撤消一個對象時,需要完成一些操作。例如,如果一個對象正在處理的是非Java 資源,如文件句柄或window 字符字體,這時你要確認在一個對象被撤消以前要保證這些資源被釋放。為處理這樣的狀況,Java 提供了被稱為收尾(finalization )的機制。使用該機制你可以定義一些特殊的操作,這些操作在一個對象將要被垃圾回收程序釋放時執(zhí)行。

要給一個類增加收尾(finalizer ),你只要定義finalize ( ) 方法即可。Java 回收該類的一個對象時,就會調(diào)用這個方法。在finalize ( )方法中,你要指定在一個對象被撤消前必須執(zhí)行的操作。垃圾回收周期性地運行,檢查對象不再被運行狀態(tài)引用或間接地通過其他對象引用。就在對象被釋放之 前,Java 運行系統(tǒng)調(diào)用該對象的finalize( ) 方法。

finalize()方法的通用格式如下:

protected void finalize( )
{
// finalization code here
}

其中,關鍵字protected是防止在該類之外定義的代碼訪問finalize()標識符。該標識符和其他標識符將在第7章中解釋。

理解finalize( ) 正好在垃圾回收以前被調(diào)用非常重要。例如當一個對象超出了它的作用域時,finalize( ) 并不被調(diào)用。這意味著你不可能知道何時——甚至是否——finalize( ) 被調(diào)用。因此,你的程序應該提供其他的方法來釋放由對象使用的系統(tǒng)資源,而不能依靠finalize( ) 來完成程序的正常操作。

注意:如果你熟悉C++,那你知道C++允許你為一個類定義一個撤消函數(shù)(destructor ),它在對象正好出作用域之前被調(diào)用。Java不支持這個想法也不提供撤消函數(shù)。finalize() 方法只和撤消函數(shù)的功能接近。當你對Java 有豐富經(jīng)驗時,你將看到因為Java使用垃圾回收子系統(tǒng),幾乎沒有必要使用撤消函數(shù)。

垃圾收集器在進行垃圾收集的時候會自動呼叫對象的finalize方法,用來進行一些用戶自定義的非內(nèi)存清理工作,因為垃圾收集器不會處理內(nèi)存以外的東西。所以,有的時候用戶需要定義一些清理的方法,比如說處理文件和端口之類的非內(nèi)存資源。

1.JVM的gc概述
  
  gc即垃圾收集機制是指jvm用于釋放那些不再使用的對象所占用的內(nèi)存。java語言并不要求jvm有gc,也沒有規(guī)定gc如何工作。不過常用的jvm都有gc,而且大多數(shù)gc都使用類似的算法管理內(nèi)存和執(zhí)行收集操作。
  
  在充分理解了垃圾收集算法和執(zhí)行過程后,才能有效的優(yōu)化它的性能。有些垃圾收集專用于特殊的應用程序。比如,實時應用程序主要是為了避免垃圾收集中斷,而大多數(shù)OLTP應用程序則注重整體效率。理解了應用程序的工作負荷和jvm支持的垃圾收集算法,便可以進行優(yōu)化配置垃圾收集器。
  
  垃圾收集的目的在于清除不再使用的對象。gc通過確定對象是否被活動對象引用來確定是否收集該對象。gc首先要判斷該對象是否是時候可以收集。兩種常用的方法是引用計數(shù)和對象引用遍歷。
  
  1.1.引用計數(shù)
  
  引用計數(shù)存儲對特定對象的所有引用數(shù),也就是說,當應用程序創(chuàng)建引用以及引用超出范圍時,jvm必須適當增減引用數(shù)。當某對象的引用數(shù)為0時,便可以進行垃圾收集。
  
  1.2.對象引用遍歷
  
  早期的jvm使用引用計數(shù),現(xiàn)在大多數(shù)jvm采用對象引用遍歷。對象引用遍歷從一組對象開始,沿著整個對象圖上的每條鏈接,遞歸確定可到達(reachable)的對象。如果某對象不能從這些根對象的一個(至少一個)到達,則將它作為垃圾收集。在對象遍歷階段,gc必須記住哪些對象可以到達,以便刪除不可到達的對象,這稱為標記(marking)對象。
  
  下一步,gc要刪除不可到達的對象。刪除時,有些gc只是簡單的掃描堆棧,刪除未標記的未標記的對象,并釋放它們的內(nèi)存以生成新的對象,這叫做清除(sweeping)。這種方法的問題在于內(nèi)存會分成好多小段,而它們不足以用于新的對象,但是組合起來卻很大。因此,許多gc可以重新組織內(nèi)存中的對象,并進行壓縮(compact),形成可利用的空間。
  
  為此,gc需要停止其他的活動活動。這種方法意味著所有與應用程序相關的工作停止,只有gc運行。結果,在響應期間增減了許多混雜請求。另外,更復雜的gc不斷增加或同時運行以減少或者清除應用程序的中斷。有的gc使用單線程完成這項工作,有的則采用多線程以增加效率。
  
2.幾種垃圾回收機制
  
  2.1.標記-清除收集器
  
  這種收集器首先遍歷對象圖并標記可到達的對象,然后掃描堆棧以尋找未標記對象并釋放它們的內(nèi)存。這種收集器一般使用單線程工作并停止其他操作。
  
  2.2.標記-壓縮收集器
  
  有時也叫標記-清除-壓縮收集器,與標記-清除收集器有相同的標記階段。在第二階段,則把標記對象復制到堆棧的新域中以便壓縮堆棧。這種收集器也停止其他操作。
  
  2.3.復制收集器
  
  這種收集器將堆棧分為兩個域,常稱為半空間。每次僅使用一半的空間,jvm生成的新對象則放在另一半空間中。gc運行時,它把可到達對象復制到另一半空間,從而壓縮了堆棧。這種方法適用于短生存期的對象,持續(xù)復制長生存期的對象則導致效率降低。
  
  2.4.增量收集器
  
  增量收集器把堆棧分為多個域,每次僅從一個域收集垃圾。這會造成較小的應用程序中斷。
  
  2.5.分代收集器
  
  這種收集器把堆棧分為兩個或多個域,用以存放不同壽命的對象。jvm生成的新對象一般放在其中的某個域中。過一段時間,繼續(xù)存在的對象將獲得使用期并轉入更長壽命的域中。分代收集器對不同的域使用不同的算法以優(yōu)化性能。
  
  2.6.并發(fā)收集器
  
  并發(fā)收集器與應用程序同時運行。這些收集器在某點上(比如壓縮時)一般都不得不停止其他操作以完成特定的任務,但是因為其他應用程序可進行其他的后臺操作,所以中斷其他處理的實際時間大大降低。
  
  2.7.并行收集器
  
  并行收集器使用某種傳統(tǒng)的算法并使用多線程并行的執(zhí)行它們的工作。在多cpu機器上使用多線程技術可以顯著的提高java應用程序的可擴展性。

3.對象的銷毀過程

在對象的銷毀過程中,按照對象的finalize的執(zhí)行情況,可以分為以下幾種,系統(tǒng)會記錄對象的對應狀態(tài):
unfinalized 沒有執(zhí)行finalize,系統(tǒng)也不準備執(zhí)行。
finalizable 可以執(zhí)行finalize了,系統(tǒng)會在隨后的某個時間執(zhí)行finalize。
finalized 該對象的finalize已經(jīng)被執(zhí)行了。

GC怎么來保持對finalizable的對象的追蹤呢。GC有一個Queue,叫做F-Queue,所有對象在變?yōu)閒inalizable的時候會加入到該Queue,然后等待GC執(zhí)行它的finalize方法。

這時我們引入了對對象的另外一種記錄分類,系統(tǒng)可以檢查到一個對象屬于哪一種。
reachable 從活動的對象引用鏈可以到達的對象。包括所有線程當前棧的局部變量,所有的靜態(tài)變量等等。
finalizer-reachable 除了reachable外,從F-Queue可以通過引用到達的對象。
unreachable 其它的對象。

來看看對象的狀態(tài)轉換圖。

20151112155733013.jpg (725×457)

好大,好暈,慢慢看。

1 首先,所有的對象都是從Reachable+Unfinalized走向死亡之路的。

2 當從當前活動集到對象不可達時,對象可以從Reachable狀態(tài)變到F-Reachable或者Unreachable狀態(tài)。

3 當對象為非Reachable+Unfinalized時,GC會把它移入F-Queue,狀態(tài)變?yōu)镕-Reachable+Finalizable。

4 好了,關鍵的來了,任何時候,GC都可以從F-Queue中拿到一個Finalizable的對象,標記它為Finalized,然后執(zhí)行它的finalize方法,由于該對象在這個線程中又可達了,于是該對象變成Reachable了(并且Finalized)。而finalize方法執(zhí)行時,又有可能把其它的F-Reachable的對象變?yōu)橐粋€Reachable的,這個叫做對象再生。

5 當一個對象在Unreachable+Unfinalized時,如果該對象使用的是默認的Object的finalize,或者雖然重寫了,但是新的實現(xiàn)什么也不干。為了性能,GC可以把該對象之間變到Reclaimed狀態(tài)直接銷毀,而不用加入到F-Queue等待GC做進一步處理。

6 從狀態(tài)圖看出,不管怎么折騰,任意一個對象的finalize只至多執(zhí)行一次,一旦對象變?yōu)镕inalized,就怎么也不會在回到F-Queue去了。當然沒有機會再執(zhí)行finalize了。

7 當對象處于Unreachable+Finalized時,該對象離真正的死亡不遠了。GC可以安全的回收該對象的內(nèi)存了。進入Reclaimed。


對象重生的例子

class C { 
  static A a; 
} 
 
class A { 
  B b; 
 
  public A(B b) { 
    this.b = b; 
  } 
 
  @Override 
  public void finalize() { 
    System.out.println("A finalize"); 
    C.a = this; 
  } 
} 
 
class B { 
  String name; 
  int age; 
 
  public B(String name, int age) { 
    this.name = name; 
    this.age = age; 
  } 
 
  @Override 
  public void finalize() { 
    System.out.println("B finalize"); 
  } 
 
  @Override 
  public String toString() { 
    return name + " is " + age; 
  } 
} 
 
public class Main { 
  public static void main(String[] args) throws Exception { 
    A a = new A(new B("allen", 20)); 
    a = null; 
 
    System.gc(); 
    Thread.sleep(5000); 
    System.out.println(C.a.b); 
  } 
} 

期待輸出

A finalize 
B finalize 
allen is 20 

但是有可能失敗,源于GC的不確定性以及時序問題,多跑幾次應該可以有成功的。詳細解釋見文末的參考文檔。

    3.1對象的finalize的執(zhí)行順序

所有finalizable的對象的finalize的執(zhí)行是不確定的,既不確定由哪個線程執(zhí)行,也不確定執(zhí)行的順序。
考慮以下情況就明白為什么了,實例a,b,c是一組相互循環(huán)引用的finalizable對象。

    3.2何時及如何使用finalize

從以上的分析得出,以下結論。
(1) 最重要的,盡量不要用finalize,太復雜了,還是讓系統(tǒng)照管比較好。可以定義其它的方法來釋放非內(nèi)存資源。
(2) 如果用,盡量簡單。
(3) 如果用,避免對象再生,這個是自己給自己找麻煩。
(4) 可以用來保護非內(nèi)存資源被釋放。即使我們定義了其它的方法來釋放非內(nèi)存資源,但是其它人未必會調(diào)用該方法來釋放。在finalize里面可以檢查一下,如果沒有釋放就釋放好了,晚釋放總比不釋放好。
(5) 即使對象的finalize已經(jīng)運行了,不能保證該對象被銷毀。要實現(xiàn)一些保證對象徹底被銷毀時的動作,只能依賴于java.lang.ref里面的類和GC交互了。

相關文章

  • Spring高階用法之自定義業(yè)務對象組件化

    Spring高階用法之自定義業(yè)務對象組件化

    這篇文章主要介紹了Spring高階用法之自定義業(yè)務對象組件化,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • Springboot自動加載配置的原理解析

    Springboot自動加載配置的原理解析

    Springboot遵循“約定優(yōu)于配置”的原則,使用注解對一些常規(guī)的配置項做默認配置,減少或不使用xml配置,讓你的項目快速運行起來,這篇文章主要給大家介紹了關于Springboot自動加載配置原理的相關資料,需要的朋友可以參考下
    2021-10-10
  • springboot logback調(diào)整mybatis日志級別無效的解決

    springboot logback調(diào)整mybatis日志級別無效的解決

    這篇文章主要介紹了springboot logback調(diào)整mybatis日志級別無效的解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-10-10
  • Java中IO流解析及代碼實例詳解

    Java中IO流解析及代碼實例詳解

    流是一種抽象概念,它代表了數(shù)據(jù)的無結構化傳遞。。用來進行輸入輸出操作的流就稱為IO流。換句話說,IO流就是以流的方式進行輸入輸出
    2021-08-08
  • java中常用的排序方法

    java中常用的排序方法

    今天給大家介紹一下,java中常用的排序方法。
    2013-04-04
  • java如何確定一個鏈表有環(huán)及入口節(jié)點

    java如何確定一個鏈表有環(huán)及入口節(jié)點

    這篇文章主要介紹了java如何確定一個鏈表有環(huán)及入口節(jié)點,想了解數(shù)據(jù)結構的同學可以參考下
    2021-04-04
  • Java中JSON字符串反序列化(動態(tài)泛型)

    Java中JSON字符串反序列化(動態(tài)泛型)

    文章討論了在定時任務中使用反射調(diào)用目標對象時處理動態(tài)參數(shù)的問題,通過將方法參數(shù)存儲為JSON字符串并進行反序列化,可以實現(xiàn)動態(tài)調(diào)用,然而,這種方式容易導致內(nèi)存溢出(OOM),這篇文章主要介紹了JSON字符串反序列化?動態(tài)泛型,需要的朋友可以參考下
    2024-12-12
  • Feign利用自定義注解實現(xiàn)路徑轉義詳解

    Feign利用自定義注解實現(xiàn)路徑轉義詳解

    這篇文章主要講解一下如何通過注解實現(xiàn)對路由中的路徑進行自定義編碼,文中的示例代碼講解詳細,對我們學習或工作有一定的幫助,需要的可以參考一下
    2022-06-06
  • java實現(xiàn)1M圖片壓縮優(yōu)化到100kb實現(xiàn)示例

    java實現(xiàn)1M圖片壓縮優(yōu)化到100kb實現(xiàn)示例

    這篇文章主要為大家介紹了java實現(xiàn)1M圖片壓縮優(yōu)化到100kb示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • Java應用開源框架實現(xiàn)簡易web搜索引擎

    Java應用開源框架實現(xiàn)簡易web搜索引擎

    本篇文章主要介紹了Java應用開源框架實現(xiàn)簡易web搜索引擎,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11

最新評論

三明市| 天柱县| 江口县| 阜康市| 依兰县| 荥阳市| 清镇市| 云南省| 盐津县| 汶川县| 茂名市| 麻城市| 渑池县| 乐山市| 英山县| 凤庆县| 石首市| 鹤岗市| 从江县| 阜新市| 汉沽区| 崇左市| 朔州市| 平乐县| 嵊泗县| 平陆县| 隆林| 德格县| 嵊州市| 娱乐| 广水市| 板桥市| 湘潭县| 略阳县| 竹山县| 宁强县| 巴林左旗| 东城区| 石城县| 久治县| 泰和县|