1.Java內存泄漏基礎知識
內存泄漏的理解其實很簡單,就是該被釋放的對象沒有被釋放,一直被某個或者某些實例引用所持有,導致不能被垃圾回收。
1)Java內存的分配策略:
a.靜態存儲區(方法區):跟堆一樣,被所有的線程共享。方法區包含所有的class和static變量,方法區中包含的都是在整個程序中永遠唯一的元素,如class,static變量。
b.棧區:每個線程包含一個棧區,棧中只保存基礎數據類型的對象和自定義對象的引用(不是對象),對象都存放在堆區中,每個棧中的數據(原始類型和對象引用)都是私有的,其他棧不能訪問,棧分爲3個部分:基本類型變量區、執行環境上下文、操作指令區(存放操作指令)。
c.堆區:動態內存分配,new出來的對象都存放在此區域,沒用的對象都會被GC進行回收。存儲的全部是對象,每個對象都包含一個與之對應的class的信息。(class的目的是得到操作指令) ,jvm只有一個堆區(heap)被所有線程共享,堆中不存放基本類型和對象引用,只存放對象本身
2、Java當中的內存泄露
在Java中,內存泄漏就是存在一些被分配的對象,這些對象有下面兩個特點,首先,這些對象是可達的,即在有向圖中,存在通路可以與其相連(也就是說仍存在該內存對象的引用);其次,這些對象是無用的,即程序以後不會再使用這些對象。如果對象滿足這兩個條件,這些對象就可以判定爲Java中的內存泄漏,這些對象不會被GC所回收,然而它卻佔用內存。簡單來說就是無用對象(不再使用的對象)持續佔有內存或者無用對象得不到及時的釋放,從而造成內存空間的浪費叫內存泄漏。
3、Android中的內存泄露
1.單例造成的內存泄漏
public class SingletonActivityContext {
private static SingletonActivityContext instance;
private Context context;
private SingletonActivityContext(Context context) {
this.context = context;
}
public static SingletonActivityContext getInstance(Context context) {
if (instance == null) {
instance = new SingletonActivityContext(context);
}
return instance;
}
}
正確寫法應該是:
public class SingletonActivityContext {
private static SingletonActivityContext instance;
private Context context;
private SingletonActivityContext(Context context) {
this.context = context.getApplicationContext(); //使用Application的context
}
public static SingletonActivityContext getInstance(Context context) {
if (instance == null) {
instance = new SingletonActivityContext(context);
}
return instance;
}
}
2.非靜態內部類創建靜態實例造成的內存泄漏
public class StaticLeakActivity extends Activity {
private static noneStaticClass mResource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (mResource == null) {
mResource = new noneStaticClass();
}
}
private class noneStaticClass {
}
}
解決:
public class StaticLeakActivity extends Activity {
private static noneStaticClass mResource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (mResource == null) {
mResource = new noneStaticClass();
}
}
//修改爲靜態內部類,這樣就不會持有外部類的引用了
private static class noneStaticClass {
}
}
3.handler造成內存泄漏
public class HandlerLeakActivity extends Activity {
private final Handler mLeakyHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLeakyHandler.postDelayed(new Runnable() {
@Override
public void run() {
}
}, 1000 * 60 * 10);
finish();
}
/*
* 解決辦法:
* 1.將 Handler 聲明爲靜態的
* 2.通過弱引用的方式引入 Activity
* 3.並在Acitivity的onDestroy()中調用handler.removeCallbacksAndMessages(null)及時移除所有消息。
*
* */
}
解決示例:
public class HandlerLeakActivity extends Activity {
private MyHandler mleakHandler = new MyHandler(this)
//1、修改爲靜態內部類
private static class MyHandler extends Handler {
//2.通過弱引用的方式引入 Activity
private WeakReference<Context> reference;
public MyHandler(Context context){
reference = new WeakReference<>(context);
}
@Override
public void handleMessage(Message msg) {
HandlerLeakActivity activity = (HandlerLeakActivity)reference.get();
if(activity!=null){
//todo業務邏輯
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLeakyHandler.postDelayed(new Runnable() {
@Override
public void run() {
}
}, 1000 * 60 * 10);
finish();
}
@Override
public void onDestroy() {
mLeakyHandler.removeCallbacksAndMessages(null);
}
}
4.線程造成的內存泄漏
public class ThreadLeakActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
testThreadLeak();
}
private void testThreadLeak() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(10000);
return null;
}
}.execute();
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(10000);
}
}).start();
}
static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private WeakReference<Context> weakReference;
public MyAsyncTask(Context context) {
weakReference = new WeakReference<>(context);
}
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(10000);
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
ThreadLeakActivity activity = (ThreadLeakActivity) weakReference.get();
if (activity != null) {
//...
}
}
}
static class MyRunnable implements Runnable {
@Override
public void run() {
SystemClock.sleep(10000);
}
}
}
5.Webview造成的內存泄漏
public class WebviewLeakActivity extends AppCompatActivity {
private WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.wv_show);
mWebView.loadUrl("http://www.baidu.com");
}
@Override
protected void onDestroy() {
destroyWebView();
//解決
//放在單獨進程中,退出殺掉進程
android.os.Process.killProcess(android.os.Process.myPid());
super.onDestroy();
}
private void destroyWebView() {
if (mWebView != null) {
mWebView.pauseTimers();
mWebView.removeAllViews();
mWebView.destroy();
mWebView = null;
}
}
}
6.資源未關閉造成的內存泄漏
7.Bitmap內存泄漏,使用recycle方法回收