🌊 博主簡介:CSDN原力作者,華為云享專家,掘金優秀作者
🌊 個人博客:haiyong.site
🌊 粉絲專屬福利:簡歷模板、PPT模板、學習資料、面試題庫,文末領取
直接跳到末尾領取資料
介紹
- 在 C/C++ 中,程式員負責物件的創建和銷毀,通常程式員會忽略無用物件的銷毀,由于這種疏忽,在某些時候,為了創建新物件,可能沒有足夠的記憶體可用,整個程式將例外終止,導致OutOfMemoryErrors,
- 但是在 Java 中,程式員不需要關心所有不再使用的物件,垃圾回識訓制自動銷毀這些物件,
- 垃圾回識訓制是守護執行緒的最佳示例,因為它始終在后臺運行,
- 垃圾回識訓制的主要目標是通過銷毀無法訪問的物件來釋放堆記憶體,
重要條款:
- 無法訪問的物件: 如果一個物件不包含對它的任何參考,則稱其為無法訪問的物件,另請注意,屬于隔離島的物件也無法訪問,
Integer i = new Integer(4);
// 新的 Integer 物件可通過 'i' 中的參考訪問
i = null;
// Integer 物件不再可用,

- 垃圾回收的資格: 如果物件無法訪問,則稱該物件有資格進行 GC(垃圾回收),在上圖中,在i = null 之后; 堆區域中的整數物件 4 有資格進行垃圾回收,
使物件符合 GC 條件的方法
-
即使程式員不負責銷毀無用的物件,但如果不再需要,強烈建議使物件不可訪問(因此有資格進行 GC),
-
通常有四種不同的方法可以使物件適合垃圾回收,
- 取消參考變數
- 重新分配參考變數
- 在方法內部創建的物件
- 隔離島
以上所有帶有示例的方法都在單獨的文章中討論:如何使物件符合垃圾收集條件
請求JVM運行垃圾收集器的方式
-
一旦我們使物件符合垃圾收集條件,垃圾收集器可能不會立即銷毀它,每當 JVM 運行垃圾收集器程式時,只會銷毀物件,但是當JVM運行Garbage Collector時,我們無法預料,
-
我們還可以請求 JVM 運行垃圾收集器,有兩種方法可以做到:
- 使用System.gc() 方法:系統類包含靜態方法gc() 用于請求 JVM 運行垃圾收集器,
- 使用Runtime.getRuntime().gc() 方法:運行時類允許應用程式與運行應用程式的 JVM 互動,因此,通過使用其 gc() 方法,我們可以請求 JVM 運行垃圾收集器,
// 演示請求 JVM 運行垃圾收集器的 Java 程式
public class Test
{
public static void main(String[] args) throws InterruptedException
{
Test t1 = new Test();
Test t2 = new Test();
// 取消參考變數
t1 = null;
// 請求 JVM 來運行垃圾收集器
System.gc();
// 取消參考變數
t2 = null;
// 請求 JVM 來運行垃圾收集器
Runtime.getRuntime().gc();
}
@Override
// 在垃圾回收之前,在物件上呼叫一次 finalize 方法
protected void finalize() throws Throwable
{
System.out.println("垃圾收集器呼叫");
System.out.println("物件垃圾收集:" + this);
}
}
輸出:
垃圾收集器呼叫
物件垃圾收集:haiyong.Test@7ad74083
垃圾收集器呼叫
物件垃圾收集:haiyong.Test@7410a1a9
- 筆記 :
- 不能保證以上兩種方法中的任何一種都一定會運行垃圾收集器,
- 呼叫System.gc() 等效于呼叫:Runtime.getRuntime().gc()
定稿
-
就在銷毀物件之前,垃圾收集器呼叫物件的finalize() 方法來執行清理活動,一旦finalize() 方法完成,垃圾收集器就會銷毀該物件,
-
finalize() 方法存在于具有以下原型的Object 類中,
protected void finalize() throws Throwable
根據我們的要求,我們可以覆寫finalize() 方法來執行我們的清理活動,例如關閉資料庫連接,
筆記 :
- 垃圾收集器而不是JVM呼叫的finalize() 方法,雖然垃圾收集器是JVM的模塊之一,
- 物件類 finalize() 方法有空實作,因此建議覆寫finalize() 方法來處理系統資源或執行其他清理,
- 對于任何給定的物件,finalize() 方法永遠不會被多次呼叫,
- 如果finalize() 方法拋出未捕獲的例外,則忽略該例外并終止該物件的終結,
有關finalize() 方法的示例,請參閱Java 程式的輸出第十套之垃圾收集
讓我們舉一個真實的例子,在那里我們使用垃圾收集器的概念,
假設你去位元組跳動實習,他們告訴你寫一個程式,計算在公司作業的員工人數(不包括實習生),要制作這個程式,你必須使用垃圾收集器的概念,
這是您在公司獲得的實際任務:-
問: 撰寫一個程式來創建一個名為 Employee 的類,該類具有以下資料成員,
1.一個ID,用于存盤分配給每個員工的唯一ID,
2.員工姓名,
3.員工年齡,
另外,提供以下方法-
- 用于初始化名稱和年齡的引數化建構式,ID 應在此建構式中初始化,
- 顯示 ID、姓名和年齡的方法 show(),
- 顯示下一個員工的 ID 的方法 showNextId(),
現在對垃圾回識訓制不了解的初學者可能會這樣撰寫代碼:
//計算在公司作業的員工人數的程式
class Employee
{
private int ID;
private String name;
private int age;
private static int nextId=1;
//它是靜態的,因為它在所有物件之間保持通用并由所有物件共享
public Employee(String name,int age)
{
this.name = name;
this.age = age;
this.ID = nextId++;
}
public void show()
{
System.out.println
("Id="+ID+"\nName="+name+"\nAge="+age);
}
public void showNextId()
{
System.out.println
("Next employee id will be="+nextId);
}
}
class UseEmployee
{
public static void main(String []args)
{
Employee E=new Employee("GFG1",33);
Employee F=new Employee("GFG2",45);
Employee G=new Employee("GFG3",25);
E.show();
F.show();
G.show();
E.showNextId();
F.showNextId();
G.showNextId();
{ //這是保留所有實習生的子塊,
Employee X=new Employee("GFG4",23);
Employee Y=new Employee("GFG5",21);
X.show();
Y.show();
X.showNextId();
Y.showNextId();
}
//這個大括號之后,X 和 Y 將被移除,因此現在它應該顯示 nextId 為 4,
E.showNextId();//這一行的輸出應該是 4,但它會給出 6 作為輸出,
}
}
輸出:

現在獲得正確的輸出:
現在垃圾收集器(gc)將看到 2 個空閑的物件,現在遞減 nextId,gc(garbage collector) 只會在我們的程式員在我們的類中覆寫它時呼叫方法 finalize() ,如前所述,我們必須請求 gc(garbage collector),為此,我們必須在關閉子塊的大括號之前撰寫以下 3 個步驟,
- 將參考設定為 null(即 X = Y = null;)
- 呼叫,System.gc();
- 呼叫,System.runFinalization();
現在計算員工人數的正確代碼(不包括實習生)
// 計算不包括實習生的員工人數的正確代碼
class Employee
{
private int ID;
private String name;
private int age;
private static int nextId=1;
//它是靜態的,因為它在所有物件之間保持通用并由所有物件共享
public Employee(String name,int age)
{
this.name = name;
this.age = age;
this.ID = nextId++;
}
public void show()
{
System.out.println
("Id="+ID+"\nName="+name+"\nAge="+age);
}
public void showNextId()
{
System.out.println
("Next employee id will be="+nextId);
}
protected void finalize()
{
--nextId;
//在這種情況下,gc 會為 2 個物件呼叫 finalize() 兩次,
}
}
// 它是 Employee 類的右括號
class UseEmployee
{
public static void main(String []args)
{
Employee E=new Employee("GFG1",33);
Employee F=new Employee("GFG2",45);
Employee G=new Employee("GFG3",25);
E.show();
F.show();
G.show();
E.showNextId();
F.showNextId();
G.showNextId();
{
//這是保留所有實習生的子塊,
Employee X=new Employee("GFG4",23);
Employee Y=new Employee("GFG5",21);
X.show();
Y.show();
X.showNextId();
Y.showNextId();
X = Y = null;
System.gc();
System.runFinalization();
}
E.showNextId();
}
}
輸出:

😊 結尾想說的
你也只需通過代碼并嘗試一下,如果大家在理解或使用代碼方面有任何困難,請在下方評論詢問,
如果你真的從這篇文章中學到了一些新東西,喜歡它,收藏它并與你的小伙伴分享,🤗最后,不要忘了?或📑支持一下哦
🌊 粉絲福利:超好玩推文定期粉絲抽獎福利
🌊 行業資料:精品PPT模板幾千套,簡歷模板一千多套
🌊 面試題庫:Java核心知識點大全和面試真題資料
🌊 學習資料:2300套PHP建站原始碼,微信小程式入門資料,Python全集(400集)
可通過下方公號回復【資源】獲取 👇🏻👇🏻👇🏻
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/301952.html
標籤:java
上一篇:java簡介
下一篇:Spring原理篇(7)--Spring最經常使用的一個功能 依賴注入, 該功能原始碼是一定需要知道的;這是我們日常開發中的核心; 了解其原始碼;這一篇就夠了;
