java的內(nèi)存分配
- 靜態(tài)存儲區(qū): 編譯時已經(jīng)分配好內(nèi)存,在程序整個運行期間都存在,主要存放靜態(tài)數(shù)據(jù)和常量
- 棧區(qū):當方法執(zhí)行時,會在棧區(qū)中創(chuàng)建方法內(nèi)部的局部變量,方法結(jié)束后自動釋放內(nèi)存
- 堆區(qū):通常用來存放new出來的對象,由java垃圾回收器回收
內(nèi)存泄露分析
永遠的singleton
由于單例的靜態(tài)特性,使得它的生命周期和應(yīng)用的生命周期一樣長。當我們使用單例的時候,要注意它內(nèi)部持有的引用,如Activity(導致Activity不能被回收)
public class Singleton{
private static Singleton singleton;
private Context context;
private Singleton(Context context){
this.context=context;
}
public static Singleton getInstance(Context context){
if(singleton==null){
singletoon=new Singleton(context);
}
return singleton;
}
}
如果該單例中需要一個Context,那么確保不要持有Activity的引用,可以使用Application提供的Context。
讓人心塞的handler
handler一般作為Acvivity的非靜態(tài)內(nèi)部類被創(chuàng)建,那么他就持有了Activity的引用,當我們發(fā)送一個延遲消息的時候,Message持有hanlder的引用,而handler持有Activity的引用,所以,當我們主動調(diào)用finish()方法的時候,Activity并不會被回收。而如果我們在Activity中需要引用外部的非static對象,應(yīng)該通過弱引用傳入。
public class DemoActivity extends Activity{
private static final class MyHandler extends Handler{
private final WeakReference<DemoActivity> mActivity;
public MyHandler(DemoActivity activity){
this.mActivity=new WeakReference<DemoActivity>(activity);
}
@override
public void handleMessage(Message msg){
DemoActivity activity=mActivity.get();
if(activity!=null){
//do sonmething
}
}
}
private final MyHandler handler=new MyHandler(this);
}
靜態(tài)內(nèi)部類不會持有外部類的引用,推薦使用靜態(tài)內(nèi)部類+弱引用,每次使用時注意進行非空判斷。
同時,在Activity被銷毀時,可以清空MessageQueue中的消息。
匿名內(nèi)部類/非靜態(tài)內(nèi)部類
一般在Activity、Fragment或者View中創(chuàng)建內(nèi)部類,如果是非靜態(tài)內(nèi)部類,則會持有外部類的引用。
而如果這個內(nèi)部類被異步線程所引用,則很可能導致內(nèi)存泄露。
public class DemoActivity extends Activity{
private static TestInnerBad testInnerBad=null;
class TestInnerBad{}
@override
public void onCreate(Bundle bundle){
if(testInnerBad==null){
testInnerBad=new TestInnerBad(); //內(nèi)存泄露
}
Runnable r1=new Runnable(){ //可能內(nèi)存泄露
@override
public void run(){
}
}
Runnable r2=new MyRunnable();
}
private static class MyRunnable implements Runnable{
@override
public void run(){}
}
}
TestInnerBad是DemoActivity的內(nèi)部類,持有他的引用,而它又被聲明為static,那么他的生命周期就和App一樣,那么肯定是造成了DemoActivity無法被正確的回收。對靜態(tài)類的正確處理方法是---單獨抽取出來封裝成一個單例。
r1是DemoActivity的匿名內(nèi)部類,他持有DemoActivity的引用,而如果r1被傳入到一個異步線程中,則很可能造成內(nèi)存泄露。
集合對象的清除
如果這個集合是static,那么該集合會一直持有傳入對象的引用,一般要在Activity、Fragment被銷毀時將集合清空。