亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android內存泄漏導致的原因有哪些

發布時間:2023-02-20 10:12:26 來源:億速云 閱讀:195 作者:iii 欄目:開發技術

這篇文章主要介紹“Android內存泄漏導致的原因有哪些”,在日常操作中,相信很多人在Android內存泄漏導致的原因有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Android內存泄漏導致的原因有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

    什么是內存泄露

    什么是內存泄露,通俗的來說就是堆中的一些對象已經不會再被使用了,但垃圾收集器卻無法將它們從內存中清除。

    內存泄漏很嚴重的問題,因為它會阻塞內存資源并隨著時間的推移降低系統性能。如果不進行有效的處理,最終的結果將會使應用程序耗盡內存資源,無法正常服務,導致程序崩潰,拋出java.lang.OutOfMemoryError異常。

    堆內存中通常有兩種類型的對象:被引用的對象和未被引用的對象。被引用的對象是應用程序中仍然具有活躍的引用,而未被引用的對象則沒有任何活躍的引用。

    垃圾收集器會回收那些未被引用的對象,但不會回收那些還在被引用的對象。這也是內存泄露發生的源頭。

    哪些操作會造成內存泄漏

    下面我們介紹幾種常見的造成內存泄露的情況

    1、意外聲明全局變量是最常見也最容易修復的內存泄漏問題,比如:

    function fn() {
        name = '張三';
    }

    解釋器在解釋上面的函數時,會把name當做全局變量,即window.name = ‘張三’。只要window對象沒有被清理,那么name屬性和屬性值將一直存在,造成內存泄露。

    解決方法:

    (1)只要在變量聲明前面加上var、let或const關鍵字即可,這樣變量就會在函數執行完畢后離開作用域。

    (2)使用this關鍵字

    function fn() {
        this.name = '張三';
    }

    (3)可以在 JavaScript 文件開頭添加 “use strict”,使用嚴格模式。這樣在嚴格模式下解析 JavaScript 可以防止意外的全局變量

    (4)在使用完之后,對其賦值為null或者重新分配

    2、 定時器導致的泄露

    let name = '張三';
    setInterval(() => {
        console.log(name);
    }, 100);

    上面的代碼中,只要定時器一直運行,回調函數中引用的name就會一直占用內存。

    3、閉包、控制臺日志、循環(在兩個對象彼此引用且彼此保留時,就會產生一個循環),下面我們看一個JavaScript閉包導致的內訓泄露例子

    let fun = function() {
        let name = '張三';
        return function() {
            return name;
        };
    };

    調用fun()會導致分配給name的內存被泄漏。以上代碼執行后創建了一個內部閉包,只要返回的函數存在就不能清理name,因為閉包一直在引用著它。

    常見內存泄露問題

    1.資源性對象未關閉

    資源性對象(如Cursor、File等一些Closeable對象),它們往往使用了緩沖區,緩沖區不僅在JVM內,JVM之外也有。如果僅僅把變量設置為null,而不關閉它們,緩沖區得不到釋放,往往造成內存泄露。

    解決方案:一般在finally中關閉資源型對象,而后設置對象為null

    2.注冊對象未注銷

    訂閱者模式中,如果注冊對象不再使用時,未及時注銷,會導致訂閱者列表中維持這對象的引用,阻止垃圾回收,導致內存泄露。常見場景:動態注冊BroadcastReceiver,注冊PhoneStateListener,注冊EventBus等等,

    還有自定義使用訂閱者模式的情形。

    解決方案:一般在onDestroy()中進行解注冊

    3.非靜態內部類的靜態實例

    非靜態內部類持有外部類實例的引用,若非靜態內部類的實例是靜態的,便擁有app存活期整個生命周期,長期持有外部類的引用,阻止外部類實例被回收。

    使用內部類的情況十分常見,尤其是匿名內部類:一些接口的匿名實現類,都是內部類。

    解決方案:(1)改為靜態內部類,不再持有外部類實例的引用 (2)避免申明非靜態內部類的靜態實例 (3)將內部類抽取出來封裝成一個單例,如果需要Context,沒有特殊要求就使用Application Context;如果需要Activity Context,則使用完畢置空,或者使用弱引用

    4.單例模式引起的內存泄露

    由于單例模式的靜態特性,使得它的生命周期和我們的應用一樣長,如果讓單例無限制的持有Activity的強引用就會導致內存泄漏

    解決方案:使用Activity的弱引用,或者沒特殊需求時使用Application Context

    5.Handler臨時性內存泄露

    非靜態Handler持有Activity或Service的引用,Message中的target指向Handler實例,所以當Message在MessageQueue中排隊,長時間未得到處理時,Activity邊不會被回收,導致臨時性內存泄露。

    解決方案:(1)使用靜態Handler內部類,然后對Handler持有的對象(Activity或Service)使用弱引用 (2)在onDestroy()中移除消息隊列中的消息 mHandler.removeCallbacksAndMessages(null)

    類似的:AsyncTask內部也是Handler機制,也存在同樣的臨時性內存泄露風險

    6.容器中對象未及時清理導致內存泄露

    容器類一般擁有較長的生命周期,若內部不再使用的對象不及時清理,內部對象邊一直被容器類引用。上述2中的訂閱者列表也屬于容器類這中情況。另外常見的容器類還有線程池、對象池、圖片緩存池等。線程池中的線程若存在ThreadLocal對象,因為線程對象一直被循環使用,ThreadLocal對象便會一直被引用,要注意對value對象的置空釋放。

    7.靜態View導致內存泄露

    有時,當一個Activity經常啟動,但是對應的View讀取非常耗時,我們可以通過靜態View變量來保持對該Activity的rootView引用。這樣就可以不用每次啟動Activity都去讀取并渲染View了。這確實是一個提高Activity啟動速度的好方法!但是要注意,一旦View attach到我們的Window上,就會持有一個Context(即Activity)的引用。而我們的View有事一個靜態變量,所以導致Activity不被回收。 解決辦法:在使用靜態View時,需要確保在資源回收時,將靜態View detach掉。

    8.屬性動畫未及時關閉導致內存泄露

    在使用ValueAnimator或者ObjectAnimator時,如果沒有及時做cancel取消動畫,就可能造成內存泄露。 因為在cancel方法里,最后調用了endAnimation(); ,在endAnimation里,有個AnimationHandler的單例,會持有屬性動畫對象的引用

    解決辦法:在在onDestory時,調用動畫的cancel方法

    9.WebView內存泄露

    目前Android中WebView的實現存在很大的兼容性問題,Google支持各個ROM廠商自行定制自己的WebView實現,各個ROM間差異較大,且大多都存在內存泄露問題。除了調用其內部的clearCache()、clearHistory()、removeAllViews()、freeMemory()、destroy()和置null以外,一般比較粗暴有效的解決方法是:將包含WebView的Activity放在一個單獨的進程中,不需要時將進程銷毀,從而釋放所有所占內存。

    10.其他的系統控件以及自定義View

    在 Android Lollipop 之前使用 AlertDialog 可能會導致內存泄漏

    view中有線程或者動畫 要及時停止。這是為了防止內存泄漏,可以在onDetachedFromWindow方法中結束,這個方法回調的時機是 當View的Activity退出或者當前View被移除的時候 會調用 這時候是結束動畫或者線程的好時機 另外還有一個對應的方法 onAttachedToWindow 這個方法調用的時機是在包含View的Activity啟動時 回調 回調在onDraw方法之前

    11.其他常見的引起內存泄漏原因

    • (1)構造Adapter時,沒有使用緩存的 contentView

    • (2)Bitmap在不使用的時候沒有使用recycle()釋放內存

    • (3)警惕線程未終止造成的內存泄露;譬如在Activity中關聯了一個生命周期超過Activity的Thread,在退出Activity時切記結束線程。一個典型的例子就是HandlerThread的run方法是一個死循環,它不會自己結束,線程的生命周期超過了Activity生命周期,我們必須手動在Activity的銷毀方法中調用thread.getLooper().quit();才不會泄露

    • (4)避免代碼設計模式的錯誤造成內存泄露;譬如循環引用,A持有B,B持有C,C持有A,這樣的設計誰都得不到釋放

    到此,關于“Android內存泄漏導致的原因有哪些”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    达日县| 秀山| 阿巴嘎旗| 晋江市| 曲阳县| 宜章县| 安化县| 益阳市| 永丰县| 万载县| 涟源市| 洪泽县| 筠连县| 工布江达县| 商洛市| 陆良县| 汤原县| 会东县| 台湾省| 垦利县| 花莲县| 临夏县| 达日县| 吴堡县| 徐州市| 姚安县| 海淀区| 仁怀市| 赣榆县| 平湖市| 德化县| 乌海市| 肥城市| 淳化县| 江城| 江口县| 南昌市| 政和县| 新化县| 临城县| 枞阳县|