摘要:內(nèi)存泄漏造成什么影響它是造成應用程序的主要原因之一。因此總結(jié)來看,線程產(chǎn)生內(nèi)存泄露的主要原因有兩點線程生命周期的不可控。造成的內(nèi)存泄漏早時期的時候處理耗時操作多數(shù)都是采用的方式,后來逐步被取代,直到現(xiàn)在采用的方式來處理異步。
目錄介紹:
01.什么是內(nèi)存泄漏
02.內(nèi)存泄漏造成什么影響
03.內(nèi)存泄漏檢測的工具有哪些
04.關(guān)于Leakcanary使用介紹
05.錯誤使用單例造成的內(nèi)存泄漏
06.Handler使用不當造成內(nèi)存泄漏
07.Thread未關(guān)閉造成內(nèi)容泄漏
08.錯誤使用靜態(tài)變量導致引用后無法銷毀
09.AsyncTask造成的內(nèi)存泄漏
10.非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實例造成內(nèi)存泄漏
11.不需要用的監(jiān)聽未移除會發(fā)生內(nèi)存泄露
12.資源未關(guān)閉造成的內(nèi)存泄漏
13.廣播注冊之后沒有被銷毀
14.錯誤使用context上下文引起內(nèi)存泄漏
15.靜態(tài)集合使用不當導致的內(nèi)存泄漏
16.動畫資源未釋放導致內(nèi)存泄漏
17.系統(tǒng)bug之InputMethodManager導致內(nèi)存泄漏
好消息博客筆記大匯總【16年3月到至今】,包括Java基礎及深入知識點,Android技術(shù)博客,Python學習筆記等等,還包括平時開發(fā)中遇到的bug匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續(xù)完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計N篇[近100萬字,陸續(xù)搬到網(wǎng)上],轉(zhuǎn)載請注明出處,謝謝!
鏈接地址:https://github.com/yangchong2...
如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起于忽微,量變引起質(zhì)變!
01.什么是內(nèi)存泄漏一些對象有著有限的聲明周期,當這些對象所要做的事情完成了,我們希望它們會被垃圾回收器回收掉。但是如果有一系列對這個對象的引用存在,那么在我們期待這個對象生命周期結(jié)束時被垃圾回收器回收的時候,它是不會被回收的。它還會占用內(nèi)存,這就造成了內(nèi)存泄露。持續(xù)累加,內(nèi)存很快被耗盡。
比如:當Activity的onDestroy()方法被調(diào)用后,Activity以及它涉及到的View和相關(guān)的Bitmap都應該被回收掉。但是,如果有一個后臺線程持有這個Activity的引用,那么該Activity所占用的內(nèi)存就不能被回收,這最終將會導致內(nèi)存耗盡引發(fā)OOM而讓應用crash掉。
02.內(nèi)存泄漏造成什么影響它是造成應用程序OOM的主要原因之一。由于android系統(tǒng)為每個應用程序分配的內(nèi)存有限,當一個應用中產(chǎn)生的內(nèi)存泄漏比較多時,就難免會導致應用所需要的內(nèi)存超過這個系統(tǒng)分配的內(nèi)存限額,這就
03.內(nèi)存泄漏檢測的工具有哪些最常見的是:Leakcanary
04.關(guān)于Leakcanary使用介紹leakCanary是Square開源框架,是一個Android和Java的內(nèi)存泄露檢測庫,如果檢測到某個 activity 有內(nèi)存泄露,LeakCanary 就是自動地顯示一個通知,所以可以把它理解為傻瓜式的內(nèi)存泄露檢測工具。通過它可以大幅度減少開發(fā)中遇到的oom問題,大大提高APP的質(zhì)量。
關(guān)于如何配置,這個就不說呢,網(wǎng)上有步驟
05.錯誤使用單例造成的內(nèi)存泄漏在平時開發(fā)中單例設計模式是我們經(jīng)常使用的一種設計模式,而在開發(fā)中單例經(jīng)常需要持有Context對象,如果持有的Context對象生命周期與單例生命周期更短時,或?qū)е翪ontext無法被釋放回收,則有可能造成內(nèi)存泄漏,錯誤寫法如下:
問題引起內(nèi)存泄漏代碼
public class LoginManager { private static LoginManager mInstance; private Context mContext; private LoginManager(Context context) { this.mContext = context; //修改代碼:this.mContext = context.getApplicationContext(); } public static LoginManager getInstance(Context context) { if (mInstance == null) { synchronized (LoginManager.class) { if (mInstance == null) { mInstance = new LoginManager(context); } } } return mInstance; } public void dealData() {} }
使用場景
在一個Activity中調(diào)用的,然后關(guān)閉該Activity則會出現(xiàn)內(nèi)存泄漏。
LoginManager.getInstance(this).dealData();
看看報錯截圖
解決辦法:
要保證Context和AppLication的生命周期一樣,修改后代碼如下:
this.mContext = context.getApplicationContext();
1、如果此時傳入的是 Application 的 Context,因為 Application 的生命周期就是整個應用的生命周期,所以這將沒有任何問題。
2、如果此時傳入的是 Activity 的 Context,當這個 Context 所對應的 Activity 退出時,由于該 Context 的引用被單例對象所持有,其生命周期等于整個應用程序的生命周期,所以當前 Activity 退出時它的內(nèi)存并不會被回收,這就造成泄漏了。
06.Handler使用不當造成內(nèi)存泄漏handler是工作線程與UI線程之間通訊的橋梁,只是現(xiàn)在大量開源框架對其進行了封裝,我們這里模擬一種常見使用方式來模擬內(nèi)存泄漏情形。
解決Handler內(nèi)存泄露主要2點
有延時消息,要在Activity銷毀的時候移除Messages
匿名內(nèi)部類導致的泄露改為匿名靜態(tài)內(nèi)部類,并且對上下文或者Activity使用弱引用。
問題代碼
public class MainActivity extends AppCompatActivity { private Handler mHandler = new Handler(); private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.text); //模擬內(nèi)存泄露 mHandler.postDelayed(new Runnable() { @Override public void run() { mTextView.setText("yangchong"); } }, 2000); } }
造成內(nèi)存泄漏原因分析
上述代碼通過內(nèi)部類的方式創(chuàng)建mHandler對象,此時mHandler會隱式地持有一個外部類對象引用這里就是MainActivity,當執(zhí)行postDelayed方法時,該方法會將你的Handler裝入一個Message,并把這條Message推到MessageQueue中,MessageQueue是在一個Looper線程中不斷輪詢處理消息,那么當這個Activity退出時消息隊列中還有未處理的消息或者正在處理消息,而消息隊列中的Message持有mHandler實例的引用,mHandler又持有Activity的引用,所以導致該Activity的內(nèi)存資源無法及時回收,引發(fā)內(nèi)存泄漏。
查看報錯結(jié)果如下:
解決方案
第一種解決辦法
要想避免Handler引起內(nèi)存泄漏問題,需要我們在Activity關(guān)閉退出的時候的移除消息隊列中所有消息和所有的Runnable。
上述代碼只需在onDestroy()函數(shù)中調(diào)用mHandler.removeCallbacksAndMessages(null);就行了。
@Override protected void onDestroy() { super.onDestroy(); if(handler!=null){ handler.removeCallbacksAndMessages(null); handler = null; } }
第二種解決方案
使用弱引用解決handler內(nèi)存泄漏問題,關(guān)于代碼案例,可以參考我的開源項目:https://github.com/yangchong2...
//自定義handler public static class HandlerHolder extends Handler { WeakReference07.Thread未關(guān)閉造成內(nèi)容泄漏mListenerWeakReference; /** * @param listener 收到消息回調(diào)接口 */ HandlerHolder(OnReceiveMessageListener listener) { mListenerWeakReference = new WeakReference<>(listener); } @Override public void handleMessage(Message msg) { if (mListenerWeakReference!=null && mListenerWeakReference.get()!=null){ mListenerWeakReference.get().handlerMessage(msg); } } } //創(chuàng)建handler對象 private HandlerHolder handler = new HandlerHolder(new OnReceiveMessageListener() { @Override public void handlerMessage(Message msg) { switch (msg.what){ case 1: TextView textView1 = (TextView) msg.obj; showBottomInAnimation(textView1); break; case 2: TextView textView2 = (TextView) msg.obj; showBottomOutAnimation(textView2); break; } } }); //發(fā)送消息 Message message = new Message(); message.what = 1; message.obj = textView; handler.sendMessageDelayed(message,time); 即推薦使用靜態(tài)內(nèi)部類 + WeakReference 這種方式。每次使用前注意判空。
當在開啟一個子線程用于執(zhí)行一個耗時操作后,此時如果改變配置(例如橫豎屏切換)導致了Activity重新創(chuàng)建,一般來說舊Activity就將交給GC進行回收。但如果創(chuàng)建的線程被聲明為非靜態(tài)內(nèi)部類或者匿名類,那么線程會保持有舊Activity的隱式引用。當線程的run()方法還沒有執(zhí)行結(jié)束時,線程是不會被銷毀的,因此導致所引用的舊的Activity也不會被銷毀,并且與該Activity相關(guān)的所有資源文件也不會被回收,因此造成嚴重的內(nèi)存泄露。
因此總結(jié)來看, 線程產(chǎn)生內(nèi)存泄露的主要原因有兩點:
1.線程生命周期的不可控。Activity中的Thread和AsyncTask并不會因為Activity銷毀而銷毀,Thread會一直等到run()執(zhí)行結(jié)束才會停止,AsyncTask的doInBackground()方法同理
2.非靜態(tài)的內(nèi)部類和匿名類會隱式地持有一個外部類的引用
例如如下代碼,在onCreate()方法中啟動一個線程,并用一個靜態(tài)變量threadIndex標記當前創(chuàng)建的是第幾個線程
public class ThreadActivity extends AppCompatActivity { private final String TAG = "ThreadActivity"; private static int threadIndex; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread); threadIndex++; new Thread(new Runnable() { @Override public void run() { int j = threadIndex; while (true) { Log.e(TAG, "Hi--" + j); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }
旋轉(zhuǎn)幾次屏幕,可以看到輸出結(jié)果為:
04-04 08:15:16.373 23731-23911/com.yc.leakdemo E/ThreadActivity: Hi--2 04-04 08:15:16.374 23731-26132/com.yc.leakdemo E/ThreadActivity: Hi--4 04-04 08:15:16.374 23731-23970/com.yc.leakdemo E/ThreadActivity: Hi--3 04-04 08:15:16.374 23731-23820/com.yc.leakdemo E/ThreadActivity: Hi--1 04-04 08:15:16.852 23731-26202/com.yc.leakdemo E/ThreadActivity: Hi--5 04-04 08:15:18.374 23731-23911/com.yc.leakdemo E/ThreadActivity: Hi--2 04-04 08:15:18.374 23731-26132/com.yc.leakdemo E/ThreadActivity: Hi--4 04-04 08:15:18.376 23731-23970/com.yc.leakdemo E/ThreadActivity: Hi--3 04-04 08:15:18.376 23731-23820/com.yc.leakdemo E/ThreadActivity: Hi--1 04-04 08:15:18.852 23731-26202/com.yc.leakdemo E/ThreadActivity: Hi--5 ...
即使創(chuàng)建了新的Activity,舊的Activity中建立的線程依然還在執(zhí)行,從而導致無法釋放Activity占用的內(nèi)存,從而造成嚴重的內(nèi)存泄漏。想要避免因為 Thread 造成內(nèi)存泄漏,可以在 Activity 退出后主動停止 Thread
例如,可以為 Thread 設置一個布爾變量 threadSwitch 來控制線程的啟動與停止
public class ThreadActivity extends AppCompatActivity { private final String TAG = "ThreadActivity"; private int threadIndex; private boolean threadSwitch = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread); threadIndex++; new Thread(new Runnable() { @Override public void run() { int j = threadIndex; while (threadSwitch) { Log.e(TAG, "Hi--" + j); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } @Override protected void onDestroy() { super.onDestroy(); threadSwitch = false; } }
如果想保持Thread繼續(xù)運行,可以按以下步驟來:
1.將線程改為靜態(tài)內(nèi)部類,切斷Activity 對于Thread的強引用
2.在線程內(nèi)部采用弱引用保存Context引用,切斷Thread對于Activity 的強引用
public class ThreadActivity extends AppCompatActivity { private static final String TAG = "ThreadActivity"; private static int threadIndex; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread); threadIndex++; new MyThread(this).start(); } private static class MyThread extends Thread { private WeakReference08.錯誤使用靜態(tài)變量導致引用后無法銷毀activityWeakReference; MyThread(ThreadActivity threadActivity) { activityWeakReference = new WeakReference<>(threadActivity); } @Override public void run() { if (activityWeakReference == null) { return; } if (activityWeakReference.get() != null) { int i = threadIndex; while (true) { Log.e(TAG, "Hi--" + i); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
在平時開發(fā)中,有時候我們創(chuàng)建了一個工具類。比如分享工具類,十分方便多處調(diào)用,因此使用靜態(tài)方法是十分方便的。但是創(chuàng)建的對象,建議不要全局化,全局化的變量必須加上static。這樣會引起內(nèi)存泄漏!
問題代碼
使用場景
在Activity中引用后,關(guān)閉該Activity會導致內(nèi)存泄漏
DoShareUtil.showFullScreenShareView(PNewsContentActivity.this, title, title, shareurl, logo);
查看報錯
解決辦法
靜態(tài)方法中,創(chuàng)建對象或變量,不要全局化,全局化后的變量或者對象會導致內(nèi)存泄漏;popMenuView和popMenu都不要全局化
知識延伸
非靜態(tài)內(nèi)部類,靜態(tài)實例化 public class MyActivity extends AppCompatActivity { //靜態(tài)成員變量 public static InnerClass innerClass = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); innerClass = new InnerClass(); } class InnerClass { public void doSomeThing() {} } } 這里內(nèi)部類InnerClass隱式的持有外部類MyActivity的引用,而在MyActivity的onCreate方法中調(diào)用了。 這樣innerClass就會在MyActivity創(chuàng)建的時候是有了他的引用,而innerClass是靜態(tài)類型的不會被垃圾回收, MyActivity在執(zhí)行onDestory方法的時候由于被innerClass持有了引用而無法被回收,所以這樣MyActivity就總是被innerClass持有而無法回收造成內(nèi)存泄露。 靜態(tài)變量引用不當會導致內(nèi)存泄漏 靜態(tài)變量Activity和View會導致內(nèi)存泄漏,在下面這段代碼中對Activity的Context和TextView設置為靜態(tài)對象,從而產(chǎn)生內(nèi)存泄漏。 public class MainActivity extends AppCompatActivity { private static Context context; private static TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = this; textView = new TextView(this); } }09.AsyncTask造成的內(nèi)存泄漏
早時期的時候處理耗時操作多數(shù)都是采用Thread+Handler的方式,后來逐步被AsyncTask取代,直到現(xiàn)在采用RxJava的方式來處理異步。這里以AsyncTask為例,可能大部分人都會這樣處理一個耗時操作然后通知UI更新結(jié)果:
問題代碼
public class MainActivity extends AppCompatActivity { private AsyncTaskasyncTask; private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.text); testAsyncTask(); finish(); } private void testAsyncTask() { asyncTask = new AsyncTask () { @Override protected Integer doInBackground(Void... params) { int i = 0; //模擬耗時操作 while (!isCancelled()) { i++; if (i > 1000000000) { break; } Log.e("LeakCanary", "asyncTask---->" + i); } return i; } @Override protected void onPostExecute(Integer integer) { super.onPostExecute(integer); mTextView.setText(String.valueOf(integer)); } }; asyncTask.execute(); } }
造成內(nèi)存泄漏原因分析
在處理一個比較耗時的操作時,可能還沒處理結(jié)束MainActivity就執(zhí)行了退出操作,但是此時AsyncTask依然持有對MainActivity的引用就會導致MainActivity無法釋放回收引發(fā)內(nèi)存泄漏
查看報錯結(jié)果如下:
解決辦法
在使用AsyncTask時,在Activity銷毀時候也應該取消相應的任務AsyncTask.cancel()方法,避免任務在后臺執(zhí)行浪費資源,進而避免內(nèi)存泄漏的發(fā)生
private void destroyAsyncTask() { if (asyncTask != null && !asyncTask.isCancelled()) { asyncTask.cancel(true); } asyncTask = null; } @Override protected void onDestroy() { super.onDestroy(); destroyAsyncTask(); }10.非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實例造成內(nèi)存泄漏
有的時候我們可能會在啟動頻繁的Activity中,為了避免重復創(chuàng)建相同的數(shù)據(jù)資源,可能會出現(xiàn)這種寫法
問題代碼
private static TestResource mResource = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(mResource == null){ mResource = new TestResource(); } } class TestResource { //里面代碼引用上下文,Activity.this會導致內(nèi)存泄漏 }
解決辦法
將該內(nèi)部類設為靜態(tài)內(nèi)部類或?qū)⒃搩?nèi)部類抽取出來封裝成一個單例,如果需要使用Context,請按照上面推薦的使用Application 的 Context。
分析問題
這樣就在Activity內(nèi)部創(chuàng)建了一個非靜態(tài)內(nèi)部類的單例,每次啟動Activity時都會使用該單例的數(shù)據(jù),這樣雖然避免了資源的重復創(chuàng)建,不過這種寫法卻會造成內(nèi)存泄漏,因為非靜態(tài)內(nèi)部類默認會持有外部類的引用,而該非靜態(tài)內(nèi)部類又創(chuàng)建了一個靜態(tài)的實例,該實例的生命周期和應用的一樣長,這就導致了該靜態(tài)實例一直會持有該Activity的引用,導致Activity的內(nèi)存資源不能正常回收。
11.不需要用的監(jiān)聽未移除會發(fā)生內(nèi)存泄露
問題代碼
//add監(jiān)聽,放到集合里面 tv.getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() { @Override public void onWindowFocusChanged(boolean b) { //監(jiān)聽view的加載,view加載出來的時候,計算他的寬高等。 } });
解決辦法
//計算完后,一定要移除這個監(jiān)聽 tv.getViewTreeObserver().removeOnWindowFocusChangeListener(this);
注意事項:
tv.setOnClickListener();//監(jiān)聽執(zhí)行完回收對象,不用考慮內(nèi)存泄漏 tv.getViewTreeObserver().addOnWindowFocusChangeListene,add監(jiān)聽,放到集合里面,需要考慮內(nèi)存泄漏12.資源未關(guān)閉造成的內(nèi)存泄漏
BroadcastReceiver,ContentObserver,F(xiàn)ileObserver,Cursor,Callback等在 Activity onDestroy 或者某類生命周期結(jié)束之后一定要 unregister 或者 close 掉,否則這個 Activity 類會被 system 強引用,不會被內(nèi)存回收。值得注意的是,關(guān)閉的語句必須在finally中進行關(guān)閉,否則有可能因為異常未關(guān)閉資源,致使activity泄漏。
13.廣播注冊之后沒有被銷毀比如我們在Activity中注冊廣播,如果在Activity銷毀后不取消注冊,那么這個廣播會一直存在系統(tǒng)中,同上面所說的非靜態(tài)內(nèi)部類一樣持有Activity引用,導致內(nèi)存泄露。因此注冊廣播后在Activity銷毀后一定要取消注冊。
在注冊觀察則模式的時候,如果不及時取消也會造成內(nèi)存泄露。比如使用Retrofit+RxJava注冊網(wǎng)絡請求的觀察者回調(diào),同樣作為匿名內(nèi)部類持有外部引用,所以需要記得在不用或者銷毀的時候取消注冊。
public class MeAboutActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.registerReceiver(mReceiver, new IntentFilter()); } private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 接收到廣播需要做的邏輯 } }; @Override protected void onDestroy() { super.onDestroy(); this.unregisterReceiver(mReceiver); } }14.錯誤使用context上下文引起內(nèi)存泄漏
先來看看造成內(nèi)存泄漏的代碼
通過查看Toast類的源碼可以看到,Toast類內(nèi)部的mContext指向傳入的Context。而ToastUtils中的toast變量是靜態(tài)類型的,其生命周期是與整個應用一樣長的,從而導致activity得不到釋放。因此,對Context的引用不能超過它本身的生命周期。
/** * 吐司工具類 避免點擊多次導致吐司多次,最后導致Toast就長時間關(guān)閉不掉了 * @param context 注意:這里如果傳入context會報內(nèi)存泄漏;傳遞activity..getApplicationContext() * @param content 吐司內(nèi)容 */ private static Toast toast; @SuppressLint("ShowToast") public static void showToast(Context context, String content) { if (toast == null) { toast = Toast.makeText(context , content, Toast.LENGTH_SHORT); } else { toast.setText(content); } toast.show(); }
解決辦法
是改為使用 ApplicationContext即可,因為ApplicationContext會隨著應用的存在而存在,而不依賴于Activity的生命周期
15.靜態(tài)集合使用不當導致的內(nèi)存泄漏有時候我們需要把一些對象加入到集合容器(例如ArrayList)中,當不再需要當中某些對象時,如果不把該對象的引用從集合中清理掉,也會使得GC無法回收該對象。如果集合是static類型的話,那內(nèi)存泄漏情況就會更為嚴重。因此,當不再需要某對象時,需要主動將之從集合中移除。
16.動畫資源未釋放導致內(nèi)存泄漏
問題代碼
public class LeakActivity extends AppCompatActivity { private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_leak); textView = (TextView)findViewById(R.id.text_view); ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(textView,"rotation",0,360); objectAnimator.setRepeatCount(ValueAnimator.INFINITE); objectAnimator.start(); } }
解決辦法
在屬性動畫中有一類無限循環(huán)動畫,如果在Activity中播放這類動畫并且在onDestroy中去停止動畫,那么這個動畫將會一直播放下去,這時候Activity會被View所持有,從而導致Activity無法被釋放。解決此類問題則是需要早Activity中onDestroy去去調(diào)用objectAnimator.cancel()來停止動畫。
@Override protected void onDestroy() { super.onDestroy(); mAnimator.cancel(); }17.系統(tǒng)bug之InputMethodManager導致內(nèi)存泄漏
每次從MainActivity退出程序時總會報InputMethodManager內(nèi)存泄漏,原因系統(tǒng)中的InputMethodManager持有當前MainActivity的引用,導致了MainActivity不能被系統(tǒng)回收,從而導致了MainActivity的內(nèi)存泄漏。查了很多資料,發(fā)現(xiàn)這是 Android SDK中輸入法的一個Bug,在15<=API<=23中都存在,目前Google還沒有解決這個Bug。
其他介紹 01.關(guān)于博客匯總鏈接1.技術(shù)博客匯總
2.開源項目匯總
3.生活博客匯總
4.喜馬拉雅音頻匯總
5.其他匯總
02.關(guān)于我的博客github:https://github.com/yangchong211
知乎:https://www.zhihu.com/people/...
簡書:http://www.jianshu.com/u/b7b2...
csdn:http://my.csdn.net/m0_37700275
喜馬拉雅聽書:http://www.ximalaya.com/zhubo...
開源中國:https://my.oschina.net/zbj161...
泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...
郵箱:yangchong211@163.com
阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV
segmentfault頭條:https://segmentfault.com/u/xi...
掘金:https://juejin.im/user/593943...
項目開源地址:https://github.com/yangchong2... 項目開源地址:https://github.com/yangchong2...文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/75015.html
摘要:然而,中依然有可能發(fā)生內(nèi)存泄漏。所以你的安卓快速定位解決內(nèi)存泄漏掘金昨天是個好日子,程序員的節(jié)日,在這里給所有的程序員送上一份遲到的祝福。應用內(nèi)存泄漏的定位分析與解決策略掘金,大家好,我是。 Android 性能優(yōu)化之巧用軟引用與弱引用優(yōu)化內(nèi)存使用 - Android - 掘金前言: 從事Android開發(fā)的同學都知道移動設備的內(nèi)存使用是非常敏感的話題,今天我們來看下如何使用軟引用與弱...
閱讀 3511·2023-04-25 14:57
閱讀 2560·2021-11-22 14:56
閱讀 2079·2021-09-29 09:45
閱讀 1761·2021-09-22 15:53
閱讀 3313·2021-08-25 09:41
閱讀 896·2019-08-29 15:22
閱讀 3289·2019-08-29 13:22
閱讀 3122·2019-08-29 13:08