日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

分析Android常見的內存泄露和解決方案

瀏覽:22日期:2022-09-17 16:20:26
目錄一、前言二、Android 內存泄露場景2.1、非靜態內部類的靜態實例2.2、多線程相關的匿名內部類/非靜態內部類2.3、Handler 內存泄露2.4、靜態 Activity 或 View2.5、Eventbus 等注冊監聽造成的內存泄露2.6、單例引起的內存泄露2.7、資源對象沒關閉造成內存泄漏2.8、WebView一、前言

目前 java 垃圾回收主流算法是虛擬機采用 GC Roots Tracing 算法。算法的基本思路是:通過一系列的名為 GC Roots (GC 根節點)的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑,當一個對象到GC Roots沒有任何引用鏈相連(圖論說:從GC Roots 到這個對象不可達)時, 證明此對象是不可用的。

關于可達性的對象,便是能與 GC Roots 構成連通圖的對象,如下圖:

分析Android常見的內存泄露和解決方案

根搜索算法的基本思路就是通過一系列名為 'GC Roots' 的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈 ( Reference Chain),當一個對象到 GC Roots 沒有任何引用鏈相連時,則證明此對象是不可用的。

從上圖,reference1、reference2、reference3 都是 GC Roots,可以看出:

reference1-> 對象實例1;

reference2-> 對象實例2;

reference3-> 對象實例4;

reference3-> 對象實例4 -> 對象實例6;

可以得出對象實例1、2、4、6都具有 GC Roots 可達性,也就是存活對象,不能被 GC 回收的對象。

而對于對象實例3、5直接雖然連通,但并沒有任何一個 GC Roots 與之相連,這便是 GC Roots 不可達的對象,這就是 GC 需要回收的垃圾對象。

在了解 GC 之后,開始去了解 Android 的內存泄露情況了。

二、Android 內存泄露場景

下面會詳細介紹一些常見的內存泄露場景,以及對應的修復辦法。

2.1、非靜態內部類的靜態實例

比如我們在 Activity 內部定義了一個內部類InnerClass,同時定義了一個靜態變量inner,并給予賦值。假設你在 onDestory 的時候沒有將 inner 置 null;那么就會引起內存泄露。原因是靜態變量持有了內部類的實例,內部類會對外部類有個引用,從而導致 Activity 得不到釋放。

private static Object inner;void createInnerClass() { class InnerClass { } inner = new InnerClass();}View icButton = findViewById(R.id.ic_button); icButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {createInnerClass();nextActivity(); }});

記得在生命周期結束的時候,將不需要的靜態變量置 null。

2.2、多線程相關的匿名內部類/非靜態內部類

和非靜態內部類一樣,匿名內部類也會持有外部類實例的引用。多線程相關的類有 AsyncTask 類,Thread 類和 Runnable 接口的類等,它們的匿名內部類如果做耗時操作

就可能發生內存泄露,這里以 AsyncTask 的匿名內部類舉例,如下所示:

void startAsyncTask() { new AsyncTask<Void, Void, Void>() {@Override protected Void doInBackground(Void... params) { while(true);} }.execute();}super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);View aicButton = findViewById(R.id.at_button);aicButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {startAsyncTask();nextActivity(); }});

當異步任務在后臺執行耗時任務期間,Activity 不幸被銷毀了(比如:用戶退出,系統回收),這個被 AsyncTask 持有的 Activity 實例就不會被垃圾回收器回收,直到異步任務結束。

解決方法是繼承 AsyncTask 新建一個靜態內部類,用靜態內部類創建實例就不會存在對外部實例的引用了。

2.3、Handler 內存泄露

同樣道理,Handler 的 message 被傳遞到消息隊列MessageQueue中,在Message消息沒有被處理之前,handler 的實例也不無法被回收,如果 handler 實例不是靜態的,就會導致引用它的 activity 或者 service 不能被回收,于是就會發生內存泄漏。

void createHandler() { new Handler() {@Override public void handleMessage(Message message) { super.handleMessage(message);} }.sendMessageDelayed(Message.obtain(), 60000);}View hButton = findViewById(R.id.h_button);hButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {createHandler();nextActivity(); }});

對于上述問題,有兩種解決辦法,一種是使用一個靜態的 handler 內部類,并且其持有的對象都改成弱引用形式進行引用。還有一種是在銷毀 activity 的時候,將發送的消息進行移除。

myHandler.removeCallbackAndMessages(null);

這種有個問題就是 Handler 中的消息可能無法全部被處理完。

另外還有一個要注意的是,最好不要直接使用 View#post 來做一些操作。如果要用,確保要用的話,確保 view 已經被 attach 到了 window。

2.4、靜態 Activity 或 View

在類中定義了靜態Activity變量,把當前運行的Activity實例賦值于這個靜態變量。如果這個靜態變量在Activity生命周期結束后沒有清空,就導致內存泄漏。因為 static 變量是貫穿這個應用的生命周期的,所以被泄漏的Activity就會一直存在于應用的進程中,不會被垃圾回收器回收。

static Activity activity;void setStaticActivity() { activity = this;}View saButton = findViewById(R.id.sa_button);saButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setStaticActivity(); nextActivity(); }});

為了能夠被回收,需要在不需要使用的時候進行置 null 操作。比如銷毀當前 activity 的時候。

特殊情況:如果一個 View 初始化耗費大量資源,而且在一個Activity生命周期內保持不變,那可以把它變成 static,加載到視圖樹上 (View Hierachy),像這樣,當Activity被銷毀時,應當釋放資源。

static view;void setStaticView() { view = findViewById(R.id.sv_button);}View svButton = findViewById(R.id.sv_button);svButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setStaticView(); nextActivity(); }});

同樣的,為了解決內存泄露的問題,在 Activity 銷毀的時候把這個 static view 置 null 即可,但是還是不建議用這個 static view的方法。

2.5、Eventbus 等注冊監聽造成的內存泄露

相信很多同學都在項目里面會用到 Eventbus。對于一些沒有經驗的同學在使用的時候經常會出現一些問題。比如說在 onCreate 的時候進行注冊,卻忘了反注冊,或者說,在onStop的時候進行反注冊,這些都會導致 Eventbus 的內存泄露。

@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); EventBus.getDefault().register(this);// 注意在onCreate()方法中注冊}@Overridepublic void onDestroy() { EventBus.getDefault().unregister(this);// 注意在onDestory()方法中注冊 super.onDestroy();}

注冊和反注冊(取消注冊)是對應的,必須要添加,否則會引起組件的內存泄漏。因為注冊的時候組件是被 EventBus 內部的單例隊列所持有引用的。

如果你是在 View 里面注冊 Eventbus 的,記得是在 View 的生命周期 onAttachedToWindow 和 onDetachedFromWindow 的時候進行注冊和反注冊。

最近跟我的同事進行聊天的時候發現,他們為了解決 eventbus 導致的內存泄露問題(已經成對注冊和反注冊還是存在內存泄露問題),于是打算創建一個 object 的實例,用這個來進行注冊與反注冊,這樣即使發生內存泄露也只會占用很小的內存空間。

2.6、單例引起的內存泄露

項目中,經常會存在很多單例。有時候需要我們將當前 Activity 實例傳給單例,然后去做一些事情。如下面的代碼:

public class SingleInstance { private Context mContext; private static SingleInstance instance; private SingleInstance(Context context) {this.mContext = context; } public static SingleInstance getInstance(Context context) {if (instance == null) { instance = new SingleInstance(context);}return instance; }}

上述單例中傳入一個 context ,就會導致 context 的生命時長和應用的生命時長一樣。就會造成內存泄露。

對于這種有三種解決辦法:

1、采用弱引用的方式進行引用,確保能夠被回收;

2、在對應的 context 要被銷毀的時候,進行置 null;確保不會長于原本的生命時長;

3、看是否能夠使用 APP context;這樣就不會存在內存泄露的問題了。

2.7、資源對象沒關閉造成內存泄漏

當我們打開資源時,一般都會使用緩存。比如讀寫文件資源、打開數據庫資源、使用 Bitmap 資源等等。當我們不再使用時,應該關閉它們,使得緩存內存區域及時回收。雖然有些對象,如果我們不去關閉,它自己在 finalize() 函數中會自行關閉。但是這得等到 GC 回收時才關閉,這樣會導致緩存駐留一段時間。如果我們頻繁的打開資源,內存泄漏帶來的影響就比較明顯了。

解決辦法:及時關閉資源

2.8、WebView

不同的Android 版本的 webView 會有差異,加上不同的廠商定制的 ROM 的 webView 差異,這就導致 webView 存在很大的兼容性問題。weView 都會存在內存泄露問題,在應用中只要使用一次,內存就不會被釋放。通常的做法是為 webView 單獨開一個進程,使用 AIDL 與應用的主進程進程通信。webView 進程可以根據業務的需求,在合適的時機進行銷毀。

以上就是分析Android常見的內存泄露和解決方案的詳細內容,更多關于Android 內存泄露和解決方案的資料請關注好吧啦網其它相關文章!

標簽: Android
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产欧美日韩精品一区二区三区 | 7m精品国产导航在线| 欧美色图一区| 国产一区调教| 狠狠久久伊人中文字幕| 国产亚洲一区二区三区啪| xxxxx性欧美特大| 国产66精品| 亚洲精品影院在线观看| 精品一区亚洲| 国产精品日本| 亚洲黄色影院| 狠狠干综合网| 米奇777超碰欧美日韩亚洲| 夜鲁夜鲁夜鲁视频在线播放| 久久精品青草| 99精品视频在线观看免费播放| 国产精品xx| 久久激情一区| 欧美成a人免费观看久久| 特黄特色欧美大片| 久久亚洲在线| 伊人久久大香线蕉av不卡| 久久久久久美女精品| 久久久久欧美精品| 久久中文字幕二区| 日韩精品一二三四| 美国三级日本三级久久99| 91精品国产乱码久久久久久久| 久久国产小视频| 一区二区三区四区在线看| 日韩在线卡一卡二| 亚洲天堂av资源在线观看| 免费国产亚洲视频| 国产午夜久久av| 福利在线一区| 免费av一区| 日韩有吗在线观看| 亚洲精品亚洲人成在线观看| 国产乱人伦丫前精品视频| 免费一级欧美片在线观看网站| 久久一区亚洲| 亚洲午夜久久久久久尤物| 国产亚洲欧洲| 国产精品一区二区三区av麻| 久久av免费看| 高清久久精品| 免费在线看一区| 中文字幕中文字幕精品| 久久精品女人| 亚洲成人va| 免费国产自线拍一欧美视频| 国产精品中文字幕亚洲欧美 | 日本va欧美va瓶| 欧美激情一区| 狠狠色狠狠色综合日日tαg| 日韩高清不卡一区| 精品国产一区二| 夜夜嗨一区二区三区| 日韩区一区二| 国产日韩欧美中文在线| 成人精品亚洲| 亚欧洲精品视频在线观看| 日韩成人免费| 在线成人直播| 亚洲综合色婷婷在线观看| 色欧美自拍视频| 久久大逼视频| 国产美女高潮在线观看| 国产农村妇女精品一区二区| 久久超级碰碰| 深夜日韩欧美| 91视频久久| 亚洲精品乱码久久久久久蜜桃麻豆| 国产精品调教| 欧美日韩一二三四| 麻豆91在线播放| 午夜久久美女| 99成人在线视频| 久久激情五月婷婷| 成人日韩精品| 国产免费av一区二区三区| 国产综合激情| 免费亚洲一区| 日韩精品欧美大片| 日韩大片在线观看| 国产欧美日韩综合一区在线播放| 九九精品调教| 青青草国产成人99久久| 中文亚洲免费| 麻豆一区二区99久久久久| 久久国产电影| 日韩av在线播放网址| 日本一区福利在线| 日韩视频免费| 国产精品第一| 亚洲一区二区成人| 激情六月综合| 国产福利一区二区三区在线播放| 亚洲tv在线| 久久中文亚洲字幕| 日韩欧美2区| 亚洲一区二区小说| 99久精品视频在线观看视频| 精品免费av| 日韩中文字幕在线一区| 日韩欧美一区免费| 久久伊人国产| 亚洲精品国产日韩| 国产精品久久久久av电视剧| 国产精品theporn| 视频一区视频二区中文| 欧美日韩国产一区二区三区不卡| 久久99国产精品视频| 亚洲精品字幕| 亚洲tv在线| 午夜亚洲福利在线老司机| 国产亚洲毛片| 久久精品国产大片免费观看| 美女久久久久久 | 免费久久精品视频| 亚洲韩日在线| 婷婷综合电影| 婷婷成人av| 久久av在线| 亚洲伊人影院| av不卡在线| 色婷婷色综合| 国产一区丝袜| 国产乱码精品一区二区三区亚洲人| 欧美日韩一区二区高清| 丝袜亚洲另类欧美| 日本少妇一区二区| 欧美视频二区| 亚洲人成网77777色在线播放| 美女久久一区| 国产亚洲高清视频| 日韩一区自拍| 久久国产影院| 欧美色图国产精品| 午夜一级在线看亚洲| 国产精品呻吟| 亚洲一区二区三区免费在线观看 | 欧美中文一区二区| 电影天堂国产精品| 91高清一区| 国产国产精品| 午夜欧美精品| 亚洲女人av| 最新国产精品视频| 国产另类在线| 久久精品一区二区国产| 国产a亚洲精品| 精品午夜av| 大香伊人久久精品一区二区| 日韩国产一区| 久久青草久久| 首页国产欧美久久| 天堂久久一区| 国产日产精品一区二区三区四区的观看方式| 欧美精品不卡| 日本一区二区高清不卡| 久久久久久网| 亚洲网站视频| 99xxxx成人网| 日韩激情中文字幕| 欧美亚洲一级| 在线人成日本视频| 快播电影网址老女人久久| 影视先锋久久| 日本一区二区中文字幕| 国产欧美日韩精品高清二区综合区| 国产成人在线中文字幕| www成人在线视频| 国产女优一区| 国产精品久久| 国产伦久视频在线观看| 欧美~级网站不卡| 蜜桃视频第一区免费观看| 久久狠狠亚洲综合| 精品三级久久| 久久国产精品毛片| 免费在线观看一区| 成人美女视频| 999国产精品视频| 少妇精品久久久| 美腿丝袜在线亚洲一区| 午夜久久美女| 国产乱码精品一区二区三区亚洲人 | 国产成人精品一区二区三区免费 | 蜜桃成人av| 日韩激情啪啪| av中文字幕在线观看第一页 | 日韩av在线中文字幕| 视频在线观看91| 久久不见久久见免费视频7 | 午夜精品久久久久久久久久蜜桃| 一区久久精品| 美女毛片一区二区三区四区最新中文字幕亚洲| 亚洲va中文在线播放免费|