內存泄漏:內存單元使用完成后未釋放,未回收。
理解強弱引用和gc垃圾回收機制后,會更好的理解內存泄漏問題。
在目前的Android項目中,內存泄漏是無法避免的,在編寫代碼時要是否產生了內存泄漏。內存泄露中要注意對象、變量等的回收時刻。
在內存泄露中,雖然存在gc回收機制,還是要搞明白,你聲明的東西是何時創建的,何時回收的。簡單來說,就是要知曉生命周期,了解越多這樣的知識,對你的代碼理解力就會有越多的提升。
一.static引發的內存泄漏:
在單例模式下,我們通常都會使用static修飾我們的對象,所以這里就要講一下static所修飾的內容的生命周期了。
static:強調一下static修飾的內容通常是不會被gc系統回收的,所以該內容就會一直存在在系統中,那么,static總是會有銷毀的時候吧:
Lifetime of a static variable: A static variable comes into existence when a class is loaded by the JVM and dies when the class is unloaded,if you create an android application and initialize a static variable, it will remain in the JVM until one of the following happens:
the class is unloaded
the JVM shuts down
the process dies
1.類被卸載的時刻。
2.JVM虛擬機關機的時刻。
3.進程被kill的時刻。
那么也就說static所修飾的內容和程序的生命周期是相關的。
接下來要說的東西就很好理解了:
1.單例模式的內存泄漏
一些單例模式中初始化時會傳入context;當你傳入Activity/Fragment的contenxt時;在該Activity/Fragment關閉,要被回收的時候,單例類還是會持有對Activity/Fragment的context引用,那么該Activity/Fragment就不會被回收,這樣就造成了內存的泄漏。所以最好的解決辦法是 傳入Application的context即可,Application就是程序,他的context就是程序的context,所以與static的生命周期相同。例:getApplicationContext()。
2.非靜態內部類創建靜態實例造成的內存泄漏
內部類的最好優勢就是默認會持有外部類的引用,而當你用這個非靜態內部類創建了一個靜態實例,那么麻煩來了,因為這個類并非靜態類,所以這個類是可以被回收的,但是靜態實例一值保持著對該非靜態類的引用,造成了非靜態內部類不能被回收,因為非靜態內部類是不能脫離所屬類而單獨存活的,那么也就導致了外部類不能被回收,內存泄漏就產生了。解決辦法當然是加上static,將非靜態內部類變成靜態內部類,靜態內部類不依賴外部類,他們擁有不同的生命周期。
1).單例模式的靜態內部類,這種寫法的單例模式是最推薦使用的單例模式(詳細可查看《Android源碼設計模式解析與實戰》)。
public class AppContext {
public static AppContext getInstance() {
return SingletonHolder.instance;
}
/**
* 靜態內部類的單例模式
*/
private static class SingletonHolder{
private static final AppContext instance = new AppContext();
}
}
復制代碼2).線程中的的內存泄漏
也可以歸到內部類的靜態使用。
線程的方式有Handler、AsyncTask、Thread等方式。
其中所有的線程方式在Activity中都是內部類的方式存在的,所以一般為了避免內存泄漏,都將這些線程實行靜態內部類的方法。在Activity被銷毀的時候,將線程關閉,清空線程中的任務。
所以一定要慎用static,在使用時要考慮到是否產生了內存泄漏。
二、資源未關閉產生的內存泄漏
這個就簡單了,在使用BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等后,要記得對資源進行手動回收,就避免了內存泄露。
有不對的地方歡迎大家指出來!
謝謝!!!