首頁 >Java >java教程 >JAVA虛擬機器學習筆記:JVM記憶體模型中垃圾回收方法

JAVA虛擬機器學習筆記:JVM記憶體模型中垃圾回收方法

php是最好的语言
php是最好的语言原創
2018-08-08 10:47:141525瀏覽

上篇文章介紹了JVM記憶體模型的相關知識,其實還有些內容可以更深入的介紹下,比如運行時常量池的動態插入,直接內存等,後期抽空再完善下上篇博客,今天來介紹下JVM中的一些垃圾回收策略。

       一、finailize()方法              

       當物件沒有任何引用的時候,通常這個物件會被回收掉,但如果我們想在物件被回收前進行一些操作,例如關閉一些資源,或者讓這個物件復活,不讓他被回收怎麼辦?這時候就要用到finailize方法了。 finailize方法是Object類別中定義的方法,表示任何一個物件都有這個方法。但這個方法只會呼叫一次,如果把這個物件復活後再次讓這個物件死亡,那第2次回收該物件的時候是不會呼叫finailize方法的,而且優先順序比較低,並不能保證一定會被執行,因此不建議使用finalize方法。總結起來就是3個特性: ①、GC之前被呼叫 。 ②、只會被呼叫一次。 ③、不可靠,不能保證被執行,不建議使用。關於finalize使用方法,參考以下程式碼:

 1 public class FinalizeTest {
 2 
 3     private static FinalizeTest test;
 4     /**
 5      * VM参数:-XX: +PrintGCDetails -Xmx=1M -Xms=1M
 6      *
 7      * @param args
 8      */
 9     public static void main(String[] args) {
10         //先对test对象赋值
11         test = new FinalizeTest();
12         int _1m = 1024 * 1024;
13         //将test置为null,便于回收
14         test = null;
15         try {
16             System.gc();
17             //模拟睡眠5s,finalize优先级较低,保证finalize能执行
18             Thread.sleep(5000);
19         } catch (InterruptedException e) {
20             e.printStackTrace();
21         }
22         if (test != null) {
23             System.out.println("first,i am alive");
24         }else{
25             System.out.println("first,i am dead");
26         }
27         //由于test在finalize方法里复活了,再次将test置为null
28         test = null;
29         try {
30             System.gc();
31             Thread.sleep(5000);//模拟睡眠5s,让GC回收
32         } catch (InterruptedException e) {
33             e.printStackTrace();
34         }
35         if (test != null) {
36             System.out.println("second,i am alive");
37         }else{
38             System.out.println("second,i am dead");
39         }
40 
41     }
42     @Override
43     protected void finalize() throws Throwable {
44         test = this ;
45         System.out.println("finalize excuted");
46         super.finalize();   //调用父类的finailize方法
47     }
48 }

JAVA虛擬機器學習筆記:JVM記憶體模型中垃圾回收方法

         程式碼運作結果如下:

          

# finalize方法執行後,test物件又重新啟動了,因此印了first,i am alive。但是第二次GC的時候,finalize方法並未被執行,因此印製了second,i am dead。前面提到finalize是優先權低不可靠的,那如果沒有Thread.sleep(5000),再來看下程式碼與結果:

JAVA虛擬機器學習筆記:JVM記憶體模型中垃圾回收方法

 1 public class FinalizeTest {
 2 
 3     private static FinalizeTest test;
 4     /**
 5      * VM参数:-XX: +PrintGCDetails -Xmx=1M -Xms=1M
 6      *
 7      * @param args
 8      */
 9     public static void main(String[] args) {
10         //先对test对象赋值
11         test = new FinalizeTest();
12         int _1m = 1024 * 1024;
13         //将test置为null,便于回收
14         test = null;
15         try {
16             System.gc();
17             //模拟睡眠5s,finalize优先级较低,保证finalize能执行
18             //不执行睡眠操作,Thread.sleep(5000);
19         } catch (Exception e) {
20             e.printStackTrace();
21         }
22         if (test != null) {
23             System.out.println("first,i am alive");
24         }else{
25             System.out.println("first,i am dead");
26         }
27         //由于test在finalize方法里复活了,再次将test置为null
28         test = null;
29         try {
30             System.gc();
31             //不执行睡眠操作,Thread.sleep(5000);//模拟睡眠5s,让GC回收
32         } catch (Exception e) {
33             e.printStackTrace();
34         }
35         if (test != null) {
36             System.out.println("second,i am alive");
37         }else{
38             System.out.println("second,i am dead");
39         }
40 
41     }
42     @Override
43     protected void finalize() throws Throwable {
44         test = this ;
45         System.out.println("finalize excuted");
46         super.finalize();   //调用父类的finailize方法
47     }
48 }

JAVA虛擬機器學習筆記:JVM記憶體模型中垃圾回收方法

##        運行結果如下:         

       這裡清楚且有清楚地看到,finalize方法的優先順序是比較低的。        關於這個例子的反思:這個例子中第一段程式碼是參考《深入理解java虛擬機》裡的程式碼實現的,但是總感覺有2點疑問:為什麼test物件是用static修飾的成員變數方式存在?如果是static修飾,那就是存在方法區了,而方法區的GC通常效果不太好的。另一個是以成員變數的方式存在,這樣finalize回收的時候,體現不出是對當前物件本身的回收,所以感覺這個例子並不是很好。       二、引用計數法

      引用計數法是一種比較早的GC回收演算法,目前一般不採用,其主要思想是:每個物件維持一個引用計數器,初始值為0,當一個物件被引用的時候,該物件的引用計數器就加1,當不被引用的時候,該物件的引用計數器就減1,如果一個物件的引用計數器變成了0,則該物件被認為是可以回收的。採用這種方式的優缺點都很明顯,優點是實現簡單,效率高,缺點是可能存在循環引用,導致記憶體溢位。     

 

三、標記-清除法

 

########       ######  標記清除法依名字分為「標記」與「清除」2個階段,其基本想法為:###先標記所有存活的對象,標記完成後,統一清除所有被標記的對象。那怎麼判斷某個物件是可以回收的呢? GC時,從一系列GC Roots根節點開始遍歷,遍歷時走過的路徑即稱為引用鏈,如果一個物件和GC Roots沒有任何引用鏈相關,那麼這個物件就不可用,就會被判定為可回收,這種演算法也叫根搜尋演算法###。那麼哪些物件可以成為GC Roots物件呢?在java語言裡,可以作為GC Roots的物件包括下面4種: ######            虛擬機堆疊中的引用變數 ######        #    方法區中的靜態屬性中的類別靜態屬性的物件參考#           方法區中的常數所引用的物件 ####

           本地方法堆疊中JNI(即native方法)的引用的物件

           標記-清除法的演算法示意圖如下:

 o ##o#o#的GC回收演算法圖片轉自一個網友的文章(點這裡),該網友的圖片內容也與原著一致,只是顏色不同。

     四、新生代的複製法

          

 複製法的基本想法是:將記憶體分為大小相等的2塊,每次只使用其中一塊,GC時每次將所有存活的物件複製到另一塊區域,然後清理該記憶體           這幾種都是方法區和堆疊中的參考物件。複製法的優點是:實現簡單,回收速度快,且不會產生記憶體碎片。但由於每次只使用其中一塊,導致記憶體使用率較低。複製演算法的示意圖如下:

相關推薦:

jvm垃圾回收演算法


##分享Java垃圾回收機制學習總結

以上是JAVA虛擬機器學習筆記:JVM記憶體模型中垃圾回收方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn