常見的內存泄漏
內存泄漏一般情況不會有,但是有了不太好找。一般內存泄漏產生的原因主要有以下幾點。
1.開發人員自己創造出來的內存泄漏代碼
2.底層依賴的代碼存在問題。
3.系統中依賴的包導致的問題。
使用底層包內存泄漏
netty中內存泄漏
https://blog.csdn.net/jiangguilong2000/article/details/42297873
日常代碼中內存泄漏
匿名內部類
和前面的非靜態內部類一樣,匿名內部類也會持有外部類實例的引用。
public class AsyncTaskActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startAsyncTask();
finish();
}
});
}
void startAsyncTask() { //啓動異步執行
new AsyncTask<Void, Void, Void>() {//異步任務在後臺執行耗時任務期間,AsyncTaskActivity被銷燬
@Override
protected Void doInBackground(Void... params) {
while (true) ; //任務持續不銷燬
}
}.execute();
}
在註釋1處實例化了一個AsyncTask,當AsyncTask的異步任務在後臺執行耗時任務期間,AsyncTaskActivity 被銷燬了,被AsyncTask持有的AsyncTaskActivity實例不會被垃圾收集器回收,直到異步任務結束。
解決辦法就是自定義一個靜態的AsyncTask
public class AsyncTaskActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startAsyncTask();
finish();
}
});
}
void startAsyncTask() {
new MyAsyncTask().execute();
}
//自定義靜態的類處理
private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
while (true) ;
}
}
}
非靜態內部類
public class SecondActivity {
private static Object inner;//靜態內部類
private Button button;
@Override
protected void on(Bundle savedInstanceState) {
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createInnerClass(); //隱式創建
finish();
}
});
}
void createInnerClass() {
class InnerClass {
}
inner = new InnerClass();//內部類的創建
}
}
非靜態內部類會持有外部類實例的引用,如果非靜態內部類的實例是靜態的,就會間接的長期維持着外部類的引用,阻止被系統回收。
Handler內存泄漏
注意兩點可能引起內存泄漏的地方
- 非靜態內部類(第一種情況)
- 有延遲消息未在onDestory中移除
Handler的Message被存儲在MessageQueue中,有些Message並不能馬上被處理,它們在MessageQueue中存在的時間會很長,這就會導致Handler無法被回收。如果Handler 是非靜態的,則Handler也會導致引用它的Activity或者Service不能被回收。
public class HandlerActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessageDelayed(Message.obtain(), 60000);
finish();
}
});
}
}
Handler 是非靜態的匿名內部類的實例,它會隱性引用外部類HandlerActivity 。上面的例子就是當我們點擊Button時,HandlerActivity 會finish,但是Handler中的消息還沒有被處理,因此HandlerActivity 無法被回收。
解決方法就是要使用一個靜態的Handler內部類,Handler持有的對象要使用弱引用,並且在Activity的Destroy方法中移除MessageQueue中的消息,如下所示。
public class HandlerActivity extends AppCompatActivity {
private Button button;
private MyHandler myHandler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
...
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myHandler.sendMessageDelayed(Message.obtain(), 60000);
finish();
}
});
}
public void show() {
}
//靜態的handler
private static class MyHandler extends Handler {
private final WeakReference<HandlerActivity> mActivity;
public MyHandler(HandlerActivity activity) {
mActivity = new WeakReference<HandlerActivity2>(activity);
}
@Override
public void handleMessage(Message msg) {
if (mActivity != null && mActivity.get() == null) {
mActivity.get().show();
}
}
}
@Override
public void onDestroy() {
if (myHandler != null) {
myHandler.removeCallbacksAndMessages(null);
}
super.onDestroy();
}
}
MyHandler是一個靜態的內部類,它持有的 HandlerActivity對象使用了弱引用,並且在onDestroy方法中將Callbacks和Messages全部清除掉。
集合中對象沒清理
,如果我們僅僅釋放引用本身,那麼Vector仍然引用該對象,所以這個對象對GC來說是不可回收的。因此,如果對象加入到Vector後,還必須從Vector中刪除,最簡單的方法就是將Vector對象設置爲null。
Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
Object o=new Object();
v.add(o);
o=null;
}
所有的Object對象都沒有被釋放,因爲變量v引用這些對象。
還有當集合裏面的對象屬性被修改後,再調用remove()方法時不起作用。
File等資源未關閉
File等,往往都用了緩衝,不使用的時候應該關閉它們。把他們的引用置爲null,而不關閉它們,往往會造成內存泄漏。
監聽器未關閉
單例模式
不正確使用單例模式是引起內存泄漏的一個常見問題,單例對象在初始化後將在JVM的整個生命週期中存在(以靜態變量的方式),如果單例對象持有外部的引用,那麼這個對象將不能被JVM正常回收,導致內存泄漏。