Re: [問題] 在物件被註銷時自動執行某些事

看板java作者 (墳墓)時間13年前 (2012/06/14 10:50), 編輯推噓7(7019)
留言26則, 7人參與, 最新討論串4/7 (看更多)
※ 引述《LaPass (LaPass)》之銘言: : 後來把那個Conn改成動態欄位,並呼叫System.gc()之後 : 連線就會被釋放了,這時候finalize也會被呼叫 這個叫你運氣好…… : 基本上是不用擔心連線被卡住的問題 : 只是系統的GC時間點..... 只要你的 JVM 還活著,RAM 又夠大,GC 可能根本就懶得回收物件。 : 也看過activity關閉重新打開之後,上次設定的static欄位的值還在之類的狀況 static 的存活和物件 instance 本來就不同,他只要 Class(不是 object) 被載 入之後就會一直在,你 activity 關掉頂多是 Activity 物件被消滅,和 static 無關。 : 我猜這跟平台的運作有關係 : 所以我不確定依靠GC去關Connection,會不會遇到什麼問題 會遇到很大、很大、很大的問題,就像有版友推文說的一樣,這幾乎等於是找 死,真的不推薦這樣做。 Java 裡面物件的消滅是 GC 在處理的,而 GC 的一個特性是你永遠不知道他什 麼時候會執行,甚至是他會不會去回收,把 conn.close() 放在 finalize() 裡 面,等於是在賭博,賭你的 JVM 會在 Connection 爆掉前回收物件,而這是很 危險的。 如果你的 RAM 夠大,JVM 活的夠久,物件不被消滅而一直佔著 Connection 的 毛坑卻不拉屎的機率是很高的,例如下面的程式碼多少可以看出這個狀況: class Resource { static int counter; int resID = 0; public Resource() { resID = counter; counter++; } public void doSomething() { System.out.println("Do something:" + resID); } @Override protected void finalize() throws Throwable { System.out.println("Cleanup Resource:" + resID); } } class Test { public static void allocateResource() { // 理論上 allocateResource() 執行完,Resource 物件就可以被回收 Resource r = new Resource(); r.doSomething(); r = null; } public static void main(String [] args) throws Exception { for (int i = 0; i < 100; i++) { allocateResource(); } // 讓 JVM 一直活著 while (true) { Thread.sleep(1000); } } } 你會發現理論上我們創造出來的一百個 Resource 物件都是可以回收的狀態,但 大部份的情況下,finalize() 根本不會去執行。 至於你一直提的到 System.gc(),JavaDoc 中講得很清楚,他是 suggest GC, 不是 force GC,你不能假設他一定會回收所有的垃圾物件。 而且現在寫 Java,幾乎都會告訴你不要使用 System.gc(),因為通常他只會托 慢你程式的速度,停下來做不一定需要做的 GC。 最後,JVM 的工程師都已經告訴你 (http://youtu.be/mumvD0r7IH4?t=25m32s)
: - Finalizer are evil - System.gc() is just as bad 幹嘛還要那麼堅持用這兩個東西啊…… 如果不想用 connection pool,又覺得自己很容易忘記 close 掉資源的話,請使 用 Java 7 的 try-with-resource 這個好朋友,又或者自己寫一個 wrapper 就 好啦。 這兩個都比依懶具有不確定性的 System.gc() 和 finalize() 好多了。 -- ~ 白馬帶著她一步步地回到中原。白馬已經老了,只能慢慢地走, 'v' Brian Hsu 但終是能回到中原的。江南有楊柳、桃花,有燕子、金魚…… // \\ ( 墳 墓 ) /( )\ 但這個美麗的姑娘就像古高昌國人那樣固執。 【白馬嘯西風】 ^`~'^ http://bone.twbbs.org.tw/blog 『那都是很好很好的,可我偏不喜歡。』 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.109.19.224 ※ 編輯: brianhsu 來自: 140.109.19.224 (06/14 10:52)

06/14 11:49, , 1F
謝謝 try-with-resource我在C#中有用過,那沒辦法達到我想
06/14 11:49, 1F

06/14 11:51, , 2F
要的功能。
06/14 11:51, 2F

06/14 22:29, , 3F
你看任何一本入門書都會告訴你,不要依賴 finalize
06/14 22:29, 3F

06/14 22:30, , 4F
作為萬一沒清理時作最後安全網是可以,依靠它則不可
06/14 22:30, 4F

06/14 23:57, , 5F
有時候,方法是會越找越奇怪的.....
06/14 23:57, 5F

06/15 00:01, , 6F
我還蠻鐵齒的,別人或是書上說不行,我會去搞懂為什麼不行
06/15 00:01, 6F

06/15 00:03, , 7F
,而不是沒搞懂就跟著說不行。
06/15 00:03, 7F
上面就已經很多人和你說過「為什麼」了,甚至我也給了你 code 告訴你: Java 裡的 GC / finalize 不一定會執行 ==> connection 不一定會關閉 這句話就算你用 System.gc() 也一樣,因為 就算系統裡有垃圾物件, System.gc() 仍然不保證會叫醒 GC,呼叫這個函式卻啥都沒發生的情形 也很多。 如果你還要堅持依賴這種不一定會執行的東西,來處理理論上一定要執行 的動作,那我也無話可說了……orz.

06/15 00:16, , 8F
你是因為一堆人沒照著規矩,才會想用這種方法吧..
06/15 00:16, 8F

06/15 00:18, , 9F
如果是別人不照規矩,你也只能確定自己有 close 就好
06/15 00:18, 9F

06/15 00:21, , 10F
在GC/Reference上動手腳,只會讓你延後遇到問題,不是解決
06/15 00:21, 10F

06/15 01:37, , 11F
那你需要的是搞懂java物件生命週期跟GC大致上是怎麼實作的.
06/15 01:37, 11F

06/15 01:41, , 12F
搞懂這兩個自然就不會去期待讓java在銷毀物件時做事
06/15 01:41, 12F
※ 編輯: brianhsu 來自: 220.137.22.123 (06/15 08:58)

06/15 09:34, , 13F
看到上一篇那幾條掛著一個多小時的連線,應該就沒人會想靠
06/15 09:34, 13F

06/15 09:36, , 14F
GC去清東西了啦.....
06/15 09:36, 14F

06/15 09:49, , 15F
還有,我不是堅持依賴那種方法,而是去想各種解決方法的可
06/15 09:49, 15F

06/15 09:50, , 16F
行性。
06/15 09:50, 16F

06/15 09:55, , 17F
不去導正觀念就只能在 work around 生態系下打泥巴戰了。
06/15 09:55, 17F

06/15 10:06, , 18F
qrtt1,現有的方法我知道,但是我想找其他方法,如此而已。
06/15 10:06, 18F

06/15 10:13, , 19F
其他方法那就是統一管理了,我們這其他人寫 query 都不會摸
06/15 10:13, 19F

06/15 10:14, , 20F
到 Connection, Statement, ResultSet 只有 sql 跟吐回 data
06/15 10:14, 20F

06/15 10:15, , 21F
資料庫看起來異常就直接修 library 更新上去就好了。
06/15 10:15, 21F

06/15 10:17, , 22F
如果你想找其他方法,那提出來的假說也不要牴觸已知
06/15 10:17, 22F

06/15 11:53, , 23F
想找其他方法之前先搞懂生命週期跟GC機制…
06/15 11:53, 23F

06/15 12:42, , 24F
如果是每本JAVA書的開頭那一兩章的內容,我已經看過很多次
06/15 12:42, 24F

06/15 12:45, , 25F
。但是還是會想去挖挖看有沒有自己不知道例外狀況,例如,
06/15 12:45, 25F

06/15 12:46, , 26F
「JAVA其實有提供干預生命週期的機制」之類的,可惜沒有。
06/15 12:46, 26F
文章代碼(AID): #1FsL5k5q (java)
討論串 (同標題文章)
文章代碼(AID): #1FsL5k5q (java)