摘要:顯而易見的,當這個是的時,就不存在內存泄漏的問題。這個我在第一期自定義如何有效保證內存泄漏問題已經說得很明白了。
內存泄漏 定義零零碎碎的東西總是記不長久,僅僅學習別人的文章也只是他人咀嚼后留下的殘渣。無意中發現了這個每日一道面試題,想了想如果只是簡單地去思考,那么不僅會收效甚微,甚至難一點的題目自己可能都懶得去想,堅持不下來。所以不如把每一次的思考、理解以及別人的見解記錄下來。不僅加深自己的理解,更要激勵自己堅持下去。
當本應該被釋放或無用的對象,因為被其他存活的對象持有其引用,導致該對象不能被垃圾回收器回收,一直占用著內存,使程序運行變得緩慢甚至崩潰。
原因為什么被其他存活的對象持有其引用,就不能被回收?這個就需要了解java的垃圾回收機制。
java垃圾回收機制
什么樣的對象會被認為需要回收呢?我們現在將每一個對象看作有向圖的結點,而對象之間的引用關系則是有向圖的邊。那么一定會有一個起始結點對象,如果這個對象是
方法區的類靜態屬性引用的對象
方法區中的常量引用的對象
本地方法棧中的native方法引用的對象
虛擬機棧(棧幀中的本地變量表(局部變量表))所引用的對象
那么由此對象可以在有向圖上遍歷到的所有對象都不會被回收。反之,就會被認為是要回收的對象。
抽象的來說,一個程序中會存在許多這樣的有向圖,如果一個對象同時被兩個存在起始結點對象的有向圖所引用。當一個有向圖完成使命,需要被銷毀,但另一個有向圖的生命周期還沒有結束。那么這個本應該無用的對象,卻不能被垃圾回收器回收,只有當另一個有向圖生命周期結束,才會被回收。
所以,就是我們常說的生命周期不同的兩個對象間有引用關系,生命周期短的可能會造成內存泄漏,持續的時間取決于生命周期長的對象。如果這個對象是靜態變量,那么將會持續到整個程序運行結束。
Android內存泄漏情況 集合類一般的集合類并不會造成內存泄漏,但是如果是全局性的集合類,如果不注意在使用完畢后進行remove操作,就極有可能造成內存泄露。
單例模式這里的單例模式是指創建時需要傳入Context作為參數。比如我們常寫的下面這個代碼。
public class Manager {
private static Manager instance;
private Context context;
private Manager(Context context){
this.context = context;
}
public static Manager getInstance(Context context){
if(instance == null){
instance = new Manager(context);
}
return instance;
}
}
關鍵就在于這個Context,如果這個Context是Activity的Content,那么顯然Activity的生命周期和單例模式的對象的生命周期是不一樣的,傳入Content的Activity使用完畢需要被回收時,是無法被垃圾回收器回收的。
顯而易見的,當這個Context是Application的時,就不存在內存泄漏的問題。因為單例模式的對象與Application的生命周期都是整個應用的生命周期,不會有任何問題。
所以,我們可以改為這樣寫
public class Manager {
private static Manager instance;
private Context context;
private Manager(Context context){
this.context = context.getApplicationContext();
}
public static Manager getInstance(Context context){
if(instance == null){
instance = new Manager(context);
}
return instance;
}
}
當然了,Application的Context也不是能隨便用的。如果是要啟動一個Activity,Application需要創建一個新的Task任務棧。而如果是創建一個Dialog,則只有Activity的context才可以。
匿名內部類對于匿名內部類,在Android中典型的例子就是Handler了吧。這個我在第一期---自定義Handler如何有效保證內存泄漏問題已經說得很明白了。主要就是匿名內部類持有外部類的引用,匿名內部類的一些操作使得該內部類對象的生命周期和外部類的生命周期不相同,造成內存泄漏。
非靜態內部類在開發中,我們為了程序的高效以及資源重復利用,我們可能會經常寫出這樣的代碼。
public class MainActivity extends BaseActivity {
private static Resource resource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(resource == null){
resource = new Resource();
}
}
class Resource{
}
}
這樣做雖然有效的避免了資源的重復創建,每次在Activity啟動時快速的使用這些資源,但卻會造成內存泄漏。因為非靜態內部類也默認會持有外部類的引用。而由于這個非靜態內部類的靜態實例,其生命周期會和整個應用程序一樣長,所以會造成內存泄露。
解決辦法就是將該內部類設為靜態內部類,或者把這個內部類抽取出來封裝成一個單例模式。
資源未關閉在我們使用BroadcastReceiver、File、Course、Stream、ContentObserver等資源或者一些框架eventbus等明確表示需要Register與unRegister時,都應該在Activity被銷毀時關閉或者注銷,否則這些資源將不會被回收。
不良代碼造成的壓力有時也并不是不能及時回收的對象造成的內存泄漏,而是有些代碼沒有及時有效的釋放不需要使用的內存,或者是沒有對于現有資源沒有有效利用而頻繁的申請新的內存,造成內存的巨大壓力。
比如ListView中的ContentView,不使用ViewHolder有效的復用View而頻繁的創建新的View,造成內存壓力。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/7047.html
摘要:但是如果你直接創建一個對象,然后重寫內部方法,那么一定會提醒你會有內存泄漏的可能。所以當的生命周期結束后,而中還存在未處理的消息,那么上面一連串的引用關系就不允許的對象被回收,就造成了內存泄漏。 零零碎碎的東西總是記不長久,僅僅學習別人的文章也只是他人咀嚼后留下的殘渣。無意中發現了這個每日一道面試題,想了想如果只是簡單地去思考,那么不僅會收效甚微,甚至難一點的題目自己可能都懶得去想,堅持不下...
閱讀 713·2023-04-25 19:43
閱讀 3910·2021-11-30 14:52
閱讀 3784·2021-11-30 14:52
閱讀 3852·2021-11-29 11:00
閱讀 3783·2021-11-29 11:00
閱讀 3869·2021-11-29 11:00
閱讀 3557·2021-11-29 11:00
閱讀 6105·2021-11-29 11:00