Java垃圾回收機制(未掌握)
垃圾回收機制
任何一種垃圾回收算法一般要做兩件基本事情:
- 發現無用的對象(沒有任何變量引用該對象)
- 回收無用對象占用的內存空間
垃圾回收相關算法: 引用計數法, 引用可達法
分代垃圾回收機制: 不同的對象的生命周期是不一樣的. 因此, 不同生命周期的對象可以采用不同的回收算法, 以便提高回收效率. 將對象分為三種狀態: 年輕代, 年老代, 持久代. JVM虛擬機將堆劃分為Eden, Survivor和Tenured/Old空間
年輕代
所有新生的對象首先是都放在Eden區. 年輕代的目標就是盡可能快速的收集掉那些生命周期短的對象, 對應的是Minor GC, 每次Minor GC會清理年輕代的內存, 算法采用效率較高的復制算法, 頻繁的操作, 但是會浪費內存空間. 當"年輕代"區域存放滿對象後, 就將對象放到年老代區域.
年老代
在年輕代中經歷了N(默認15)次垃圾回收後仍然存活的對象, 就會放到年老代中. 因此, 可以認為年老代中存放的都是一些生命周期較長的對象. 年老代對象越來越多, 我們就需要啟動Magor GC和Full GC(全量回收), 來一次大掃除, 全面清理年輕代區域和年老代區域
持久代
用於存放靜態文件, 如Java類, 方法等. 持久代堆垃圾回收沒有顯著影響
Minor GC: 用於清理年輕代區域. Eden區滿了就會觸發一次Minor GC.清理無用對象, 將有用對象復制到"Survivor1", "Survivor2"區中(這兩個區大小相同, 同一時刻兩者只有一個在用, 另一個為空)
Full GC: 用於清理年輕代, 年老代區域. 成本較高, 會對系統性能產生影響
垃圾回收過程:
- 新創建的對象, 絕大多數都會存儲在Eden中
- 當Eden滿了(到達一定比例)不能創建新對象, 則觸發垃圾回收(GC), 將無用對象清理掉, 然後剩余對象復制到某個Survivor中, 同時清空Eden區
- 當Eden區再次滿了, 會將Survivor中不能清空的對象存到另一個Survivor中
- 重復多次(默認15次)Survivor中沒有被清理的對象, 則會復制到年老代Old(Tenured)區中
- 當Old區滿了, 就會觸發一個一次完整的垃圾回收(Full GC), 之前新生代的垃圾回收稱為(minor GC)
垃圾回收機制關鍵點:
垃圾回收機制只回收JVM堆內存裏的對象空間
對其他物理連接, 比如數據庫連接, 輸入流輸出流, Socket連接無能為力
現在的JVM有多種垃圾回收實現算法, 表現各異
垃圾回收發生具有不可預知性, 程序無法精確控制垃圾回收機制執行
可以將對象的引用變量設置為null, 暗示垃圾回收機制可以回收該對象
程序員可以通過System.gc()或者Runtime.getRuntime().gc()來通知系統進行垃圾回收, 會有一些效果, 但是系統是否進行垃圾回收依然不確定
垃圾回收機制回收任何對象之前, 總會先調用它的finalize方法(如果覆蓋該方法, 讓一個新的引用變量重新引用該對象, 則會重新激活對象)
永遠不要主動調用某個對象的finalize方法, 應該交給垃圾回收機制調用
易造成內存泄漏的操作
創建大量無用對象
如在需要大量拼接字符串時, 使用String而不是StringBuilder
String str = --;
for(int = 0; i < 10000; i++) {
str += i; // 相當於產生了10000個String對象
}
靜態集聚合類的使用
像HashMap, Vector, List等的使用最容易出現內存泄漏, 這些靜態變量的生命周期和應用程序一致, 所有的對象Object也不能被釋放
各種連接對象(IO流對象, 數據庫連接對象, 網絡連接對象)未關閉
IO流對象, 數據庫連接對象, 網絡連接對象等連接對象屬於物理連接, 和硬盤或者網絡連接, 不使用是一定要關閉
監聽器的使用
- 程序員無權調用垃圾回收器
- 程序員可以調用System.gc(), 該方法只是通知JVM, 並不是運行垃圾回收器. 盡量少使用, 會申請啟動Full GC, 成本高, 影響系統性能
- finalize方法, 是Java提供給程序員來釋放對象或資源的方法, 但是盡量少使用
Java垃圾回收機制(未掌握)