文章目錄
- 靜態實體持有非靜態內部類
- 描述🤦?♀?
- 解決辦法🙆?♀?
- 耗時任務相關的匿名內部類/非靜態內部類
- 描述🤦?♀?
- 解決方案🙆?♀?
- Handle記憶體泄漏
- 描述🤦?♀?
- 解決方案🙆?♀?
- Context被長期持有
- 描述🤦?♀?
- 解決方案🙆?♀?
- View被靜態修飾
- 描述🤦?♀?
- 解決方案🙆?♀?
- 大物件/監聽器釋放
- 描述🤦?♀?
- 解決方案🙆?♀?
- 資源物件注意關閉
- 描述🤦?♀?
- 解決方案🙆?♀?
- 集合物件
- 描述🤦?♀?
- 解決方案🙆?♀?
對常見的記憶體泄漏進行一波總結,希望可以幫到大家,
靜態實體持有非靜態內部類
描述🤦?♀?
非靜態內部類會持有外部類的實體,所以如果非靜態內部類的實體是靜態的話,那么它的生命周期就是整個APP的生命周期,而它則會一直持有外部類的參考,阻止外部類實體被系統回收,
舉個例子🌰:
public class TestActivity extends AppCompatActivity {
static InnerClass innerClass;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.item_layout);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
innerClass = new InnerClass();
}
});
}
class InnerClass{}
}
此時點擊button時,會創建InnerClass實體并且賦值給innerClass,因為innerClass被static修飾,所以InnerClass實體的生命周期會和應用程式一樣長,但是它會持有TestActivity的實體,所以就會導致如果系統需要回收不了TestActivity的實體,造成記憶體泄漏😮,
解決辦法🙆?♀?
- 將非靜態內部類替換成靜態內部類,因為靜態內部類不會持有外部類的參考
- 一定要用非靜態內部類的話,要保證內部類的生命周期短于外部類
耗時任務相關的匿名內部類/非靜態內部類
描述🤦?♀?
這個和上一個類似,非靜態內部類持有外部類的實體大家都知道了,這里不在敘述了;匿名內部類也會持有外部類的實體,而且匿名內部類會結合執行緒使用得多,這里就拉出來講一下,
同理因為匿名內部類會持有外部類的實體,比如執行緒的Runable如果在里面做了耗時任務,在外部類物件需要回收的時候,但是執行緒任務沒有執行完,那么就會因為匿名內部類持有外部類的參考,進而阻止系統回收外部類物件了,
簡單舉個例子🌰
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.item_layout);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.MICROSECONDS, new SynchronousQueue(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(new ThreadGroup("test-thread"),r);
}
});
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
while (true){
Log.d("TAG", "run: test");
}
}
});
}
});
}
}
點擊button執行執行緒任務,提交了一個runable進去,因為里面死回圈永遠不會結束,所以匿名內部類會一直持有TestActivitty物件,不會被系統回收掉😮,因為匿名內部類這玩意進場使用,所以還是需要注意的!!!🤦?♀?
解決方案🙆?♀?
- 將匿名內部類/非靜態內部類替換成靜態內部類,因為靜態內部類不會持有外部類的參考
- 一定要用匿名內部類/非靜態內部類的話,要保證內部類的生命周期短于外部類
Handle記憶體泄漏
描述🤦?♀?
這個就有點老生常談了😂,但還是的說一下,
Handler發送的Message會存盤在MessageQueue里面,但是他們不一定馬上就被處理了,
另外我們知道Message的Target會持有記錄當前的Handler物件,用于進行訊息分發,所以如果Message不被及時處理,那么Handler就無法被回收,
那么如果此時Handler是非靜態的,則Handler也會導致參考它的Activity不能被回收😮,
舉個例子🌰
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.item_layout);
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessageDelayed(new Message(),100000);
finish();
}
});
}
}
當點擊button時,會finish當前activity,但是因為訊息沒有被及時處理,間接參考了Handler物件,Handler又是匿名內部類實體,持有了activity物件,所以導致記憶體泄漏🤦?♀?,
解決方案🙆?♀?
-
使用靜態Handler內部類,handler的持有者用弱參考,
-
在onDestroy中將未執行的訊息和Callbacks清除,
if (mHandler != null) { mHandler.removeCallbacksAndMessages(null); }
Context被長期持有
描述🤦?♀?
這個也很簡單,比如你把Activity的Context傳給了一個長期存在的物件,那其實activity的context就是它自身,那么因為被持有就回收不了,造成記憶體泄漏
解決方案🙆?♀?
- 對于不是必須使用Activity的Context的情況(Dialog的Context必須使用Activity的Context),可以考慮使用Application來代替Activity的Context,因為一般使用Context無非時獲取一些資源而已,
- 一定要傳入Activity的Context的話,一定要注意生命周期,不可以被長期參考,
View被靜態修飾
描述🤦?♀?
這個,,,,我估計沒有多少人這么使用吧,如果View被靜態修飾的話,因為View會持有Context,所以就會導致當前Activity不會被回收,🤦?♀?
舉個例子🌰
public class TestActivity extends AppCompatActivity {
static View button;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.item_layout);
button = findViewById(R.id.button);
}
}
解決方案🙆?♀?
- 在onDestory中將view置null,
大物件/監聽器釋放
描述🤦?♀?
大物件比如Bitmap
Bitmap物件一般比較大,而且好多操作都需要變換產生新的物件,所以需要注意一定要盡快釋放臨時的Bitmap物件用于節省記憶體,盡量避免被靜態修飾或者其他長生命周期參考,
監聽器的釋放
很多服務需要register和unregister監聽器,需要在合適的時候及時的unregister這些監聽器否則容易產生記憶體泄漏,
解決方案🙆?♀?
- 大物件及時釋放
- 監聽器在合適的時候進行釋放
資源物件注意關閉
描述🤦?♀?
資源物件比如File、Cursor等,如果不進行正常關閉,會造成記憶體泄漏,
解決方案🙆?♀?
- 通常使用例外代碼塊捕獲,在finally陳述句中進行關閉,防止出現例外資源沒有被正常釋放問題,
集合物件
描述🤦?♀?
注意一些生命周期很長的集合,比如被static修飾的集合,它的生命周期會時APP的生命周期,那么它里面維持的物件,如果在沒用之后要即使清理掉,否則就會造成記憶體泄漏,
舉個例子🌰
public class TestActivity extends AppCompatActivity {
static List<View> vies;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.item_layout);
vies.add(findViewById(R.id.button));
}
}
view被加入集合,因為集合生命周期為APP的生命周期,所以View、Activity也回收不了,記憶體泄漏,
解決方案🙆?♀?
- 這個完全需要自己注意,對于長生命周期集合內部物件的管理,
創作不易,如有幫助一鍵三連咯🙆?♀?,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/386645.html
標籤:其他
