怎麼解決引用計數 GC 的迴圈引用問題?
引用計數方式 GC 存在迴圈引用問題,導致無法辨別無用物件,而 GC ROOT 方式不存在迴圈引用的問題
引用計數和 GC ROOT 的實現機理很易理解,面試時大家都能流利應答,那怎麼才能脫穎而出呢?思考一個問題:不通過 GC ROOT,仍使用引用計數方式,怎麼解決它的迴圈引用問題?
解答此問題前,通過目標驅動法來想象一下,若 Get 了此知識點,可以這樣應用到面試中:
面試官: 說一下垃圾回收機制吧
我: ...可以通過強、弱引用計數結合方式解決引用計數的迴圈引用問題,實際上 Android 的智慧指標就是這樣實現的...
智慧指標
智慧指標在整個 Android 工程中使用很廣泛,在 binder 相關原始碼可以看到 sp、wp 型別的引用:
sp<IBinder> result = new BpBinder(handle);
wp<IBinder> result = new BpBinder(handle);
sp 即 strong pointer 強指標引用;wp 是 weak pointer 弱指標引用。
在 Java 中我們不用關心物件的銷燬及記憶體釋放,GC 機制會自動辨別回收無用物件,而 智慧指標 就是 native 層一個小型的 GC 實現。
智慧指標以引用計數的方式來標識無用物件,使用智慧指標的物件需繼承自 RefBase,RefBase 中維護了此物件的強引用數量和弱引用數量。
強指標 sp 過載了 "=" 運算子,在引用其他物件時將強引用計數 +1,在 sp 解構函式中將強引用計數 -1,當強引用計數減至 0 時銷燬引用的物件,這樣就實現了物件的自動釋放。
弱指標引用其他物件時將弱引用計數 +1,在 wp 解構函式中將弱引用計數 -1,當強引用計數為 0 時,不論弱引用計數是否為 0 都銷燬引用的物件。
如何解決迴圈引用問題
只靠強引用計數方式,會存在迴圈引用的問題,導致物件永遠無法被釋放,弱引用就是專門用來解決迴圈引用問題的:
若 A 強引用了 B,那 B 引用 A 時就需使用弱引用,當判斷是否為無用物件時僅考慮強引用計數是否為 0,不關心弱引用計數的數量
這樣就解決了迴圈引用導致物件無法釋放的問題,但這會引發野指標問題:當 B 要通過弱指標訪問 A 時,A 可能已經被銷燬了,那指向 A 的這個弱指標就變成野指標了。在這種情況下,就表示 A 確實已經不存在了,需要進行重新建立等其他操作
智慧指標自定義規則
智慧指標並不是固定的 "當強引用計數為 0 時,不論弱引用計數是否為 0 都銷燬引用的物件" ,而是可以自定義規則。RefBase 提供了 extendObjectLifetime() 方法,可以用來設定引用計數器的規則,不同規則對刪除目標物件的時機判斷也是不一樣的,包括以下三種規則:
-
OBJECT_LIFETIME_STRONG:只有在這個物件記憶體空間中的強計數器值為 0 的時候才會銷燬物件
-
OBJECT_LIFETIME_WEAK:只有在這個物件記憶體空間中的強計數器和弱計數器的值都為 0 的時候才會銷燬物件
-
OBJECT_LIFETIME_MASK:不管這兩個計數器是不是都為 0,都不銷燬物件,即與一般指標無異,還是要自己手動去釋放物件
作者:位元組走動_Android
連結:https://www.jianshu.com/p/519a2b76d4d4
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
相關文章
- 解決迴圈引用
- 【FastJSON】解決FastJson中“$ref 迴圈引用”的問題ASTJSON
- require()迴圈引用問題UI
- FastJson中迴圈引用的問題ASTJSON
- Unity容器建構函式引數迴圈引用問題及解決Unity函式
- Python迴圈引用是什麼?如何避免迴圈引用?Python
- SpringBoot 迴圈引用解決辦法Spring Boot
- JavaScript 深複製的迴圈引用問題JavaScript
- Block迴圈引用的三種解決方式BloC
- NSTimer迴圈引用的幾種解決方案
- 迴圈引用
- iOS | 用於解決迴圈引用的block timeriOSBloC
- Spring如何解決迴圈引用Spring
- 如何解決使用JSON.stringify時遇到的迴圈引用問題JSON
- iOS迴圈引用iOS
- ARC下的block導致的迴圈引用問題解析BloC
- 透過迴圈引用問題來分析Spring原始碼Spring原始碼
- Swift與OC真正去理解Block解決迴圈引用的技巧SwiftBloC
- iOS 關於NSTimer的迴圈引用iOS
- 使用c#強大的表示式樹實現物件的深克隆之解決迴圈引用的問題C#物件
- iOS-block迴圈引用詳解和應用iOSBloC
- [NG] 考古 - HttpInterceptor 迴圈引用錯誤HTTP
- 解決NSTimer迴圈引用導致記憶體洩漏的六種方法記憶體
- Flask中的迴圈引用/匯入問題演示以及解決方案 | 藍圖的使用與解析 | 藍圖額外用法Flask
- 全域性元件實現遞迴樹,避免迴圈引用元件遞迴
- PHP的引用計數是什麼意思?PHP
- Spring的3級快取和迴圈引用的理解Spring快取
- Spring怎麼解決迴圈依賴?Spring
- Swift - 使用 Protocol 避免框架之間迴圈引用SwiftProtocol框架
- 迴圈引用導致的json序列化失敗JSON
- Rust 程式設計影片教程(進階)——015_1 引用迴圈Rust程式設計
- 解決VUE引用element不能顯現元件css樣式問題Vue元件CSS
- iOS 進階 - 記憶體管理(八) -- 迴圈引用iOS記憶體
- Spring 迴圈引用(三)原始碼深入分析版Spring原始碼
- Java四大引用詳解:強引用、軟引用、弱引用、虛引用Java
- Java虛擬機器-GC垃圾回收演算法-引用計數法Java虛擬機GC演算法
- 使用 foreach 使用引用變數需要注意的問題變數
- Rust 程式設計視訊教程(進階)——015_1 引用迴圈Rust程式設計