java是如何做資源回收補救的
學習java的過程,我們經常談論一個物件的回收,尤其是資源型別,如果沒有顯示的關閉,物件就被回收了,說明出現了資源洩漏。java本身為了防止這種情況,做了一些擔保的方式,確保可以讓未關閉的資源合理回收掉。
finalize回收
finalize方式是java物件被回收時觸發的一個方法。java的很多資源物件,都是在finalize中寫了擔保的方法。
/**
* Ensures that the <code>close</code> method of this file input stream is
* called when there are no more references to it.
*
*
@exception IOException if an I/O error occurs.
*
@see java.io.FileInputStream#close()
*/
protected
void
finalize
()
throws IOException {
if ((fd !=
null) && (fd != FileDescriptor.in)) {
/* if fd is shared, the references in FileDescriptor
* will ensure that finalizer is only called when
* safe to do so. All references using the fd have
* become unreachable. We can call close()
*/
close();
}
}
上面是FileInputStream的finalize方法,在方法被呼叫時,會檢測檔案描述符是否存在,如果存在的話就呼叫close方法。來確保資源的回收。
finalize方法在我們學習java的時候都並不推薦進行重寫,也不推薦寫複雜的邏輯在裡面,主要是因為gc的時候,都會呼叫這個方法,如果執行的內容太多,就會導致gc被拖長。影響程式的正常執行。而且這裡也只是做一個簡單的擔保。大部分希望的還是編寫程式碼的人可以呼叫close。這樣在做判斷的時候就結束了,而不用真正的呼叫關閉的程式碼。
Cleaner回收
在DirectByteBuffer中,使用了一個Cleaner物件進行補救的。
unsafe.setMemory(
base, size, (
byte)
0);
if (pa && (
base % ps !=
0)) {
// Round up to page boundary
address = base + ps - (base & (ps - 1));
} else {
address = base;
}
cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
att = null;
申請完資源後,會建立一個Deallocator物件。
private
static
class
Deallocator
implements
Runnable
{
private
static Unsafe unsafe = Unsafe.getUnsafe();
private
long address;
private
long size;
private
int capacity;
private
Deallocator
(
long address,
long size,
int capacity) {
assert (address !=
0);
this.address = address;
this.size = size;
this.capacity = capacity;
}
public
void
run
() {
if (address ==
0) {
// Paranoia
return;
}
unsafe.freeMemory(address);
address = 0;
Bits.unreserveMemory(size, capacity);
}
}
Deallocator的run方法中就進行了資源的釋放。執行的時機就是靠 Cleaner來觸發的。Cleaner是PhantomReference的子類,PhantomReference是Reference的子類。在中有一個ReferenceHandler
private
static
class
ReferenceHandler
extends
Thread {
他的run方法就是呼叫cleaner裡的clean方法。這個執行緒是在靜態塊裡啟動起來的。
Thread handler =
new ReferenceHandler(tg,
"Reference Handler");
/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(
true);
handler.start();
SharedSecrets.setJavaLangRefAccess(
new JavaLangRefAccess() {
@Override
public
boolean
tryHandlePendingReference
() {
return tryHandlePending(
false);
}
});
於此同時,並且給SharedSecrets設定了一個JavaLangRefAccess。呼叫clean方法的過程在tryHandlePending裡,這裡的引數很重要。
static boolean tryHandlePending(boolean waitForNotify) {
Reference<Object> r;
Cleaner c;
try {
synchronized (lock) {
if (pending !=
null) {
r = pending;
//
'instanceof' might
throw OutOfMemoryError sometimes
// so
do
this before un-linking
'r'
from the
'pending' chain...
c = r
instanceof Cleaner ? (Cleaner) r :
null;
// unlink
'r'
from
'pending' chain
pending = r.discovered;
r.discovered =
null;
}
else {
// The waiting
on the lock may cause an OutOfMemoryError
// because it may
try to allocate exception objects.
if (waitForNotify) {
lock.wait();
}
// retry
if waited
return waitForNotify;
}
}
}
catch (OutOfMemoryError x) {
// Give other threads CPU time so they hopefully drop some live references
//
and GC reclaims some space.
// Also prevent CPU intensive spinning
in case
'r instanceof Cleaner' above
// persistently throws OOME
for some time...
Thread.
yield();
// retry
return
true;
}
catch (InterruptedException x) {
// retry
return
true;
}
waitForNotify是true的時候,在沒有回收物件的時候,會進入阻塞,然後等ooe。外層是個死迴圈,就會被再次呼叫到,下次進來的時候就可以出發clean了。ReferenceHandler是管理機制的一種。還有一種就是SharedSecrets呼叫tryHandlePending(false)。在另外一個類,bits裡
final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
// retry
while helping enqueue pending Reference objects
//
which includes executing pending Cleaner(s)
which includes
// Cleaner(s) that free direct buffer memory
while (jlra.tryHandlePendingReference()) {
if (tryReserveMemory(size,
cap)) {
return;
}
}
在做reserveMemory的時候,會從SharedSecrets來呼叫tryHandlePending(false)。這裡又變相的進行了一次回收。
小結
java回收利用兩種機制。一種是finalize,一種是Cleaner。其中Cleaner一部分依賴oome觸發一次回收,一部分利用reserveMemory中做一次回收
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69923331/viewspace-2701192/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java垃圾回收是如何工作的?Java
- jdbc資源的回收問題!JDBC
- C# 資源回收C#
- 如何補救因疫情被延期的專案
- 疫情期間延期的專案如何補救
- CentOS7 官網停更後的補救措施CentOS
- Linux :忘記使用nohup該如何補救Linux
- 邦芒攻略:面試遲到該如何補救面試
- Oracle Exp誤匯入系統帳號的補救方法Oracle
- JVM救不了Java(轉載)JVMJava
- jenkins忘記管理員登陸密碼的補救措施Jenkins密碼
- 不規範變數名的痛處和一點補救變數
- Java中的垃圾回收Java
- 關於使用GHOST後硬碟分割槽整合,資料丟失補救方法(轉)硬碟
- 開源搜尋引擎排名第一,Elasticsearch是如何做到的?Elasticsearch
- 如何做一份完善的補丁分析
- 開車誤闖紅燈的補救方法(以及由此引發的一些思考)
- Java垃圾回收Java
- 救基友記2_JAVAJava
- 資料放在隨身碟了,以為丟了,瞎忙活一天補救……
- Java虛擬機器-GC垃圾回收演算法-判定一個物件是否是可回收的物件Java虛擬機GC演算法物件
- Java的垃圾回收機制Java
- 【知識分享】伺服器被攻擊後如何補救伺服器
- Mensa是Java的模式匹配開源庫Java模式
- Java——GC(垃圾回收)JavaGC
- 遊戲產品如何做優化(五):LTV回收拆解遊戲優化
- redis 是如何做持久化的Redis持久化
- 資源|機器學習必知的15大框架,歡迎補充!機器學習框架
- C++的救贖 C++開源程式庫評話(轉)C++
- Webpack的熱更新是如何做到的?原理是什麼?Web
- 低資源神經機器翻譯MetaNMT :來自MAML與NLP的溫柔救贖
- java垃圾回收機制Java
- Java 垃圾回收機制Java
- jvm java回收機制JVMJava
- Java的垃圾回收(Garbage Collection)機制Java
- Java的四種引用和回收策略Java
- 不同Java垃圾回收器的比較Java
- Java的記憶體回收機制Java記憶體