4、Android內(nèi)存泄漏問(wèn)題

問(wèn)題:

1、 內(nèi)存泄漏與內(nèi)存溢出的區(qū)別?
2、 垃圾回收機(jī)制的原理是什么?
3、 什么情況下會(huì)出現(xiàn)Android內(nèi)存泄漏(六大類)
4、 什么是內(nèi)存抖動(dòng),造成的本質(zhì)是什么?(年輕堆與老年堆)
5、 怎么處理Crash異常,對(duì)于不能定位行數(shù)的問(wèn)題怎么解決

1、 內(nèi)存泄漏與內(nèi)存溢出的區(qū)別?

內(nèi)存溢出

指程序在申請(qǐng)內(nèi)存時(shí), 沒(méi)有足夠的內(nèi)存空間供其使用,出現(xiàn)out of memory (OOM)。Android系統(tǒng)為每個(gè)應(yīng)用程序申請(qǐng)到的內(nèi)存有限,一般為64M或者128M等,我們可以在清單文件中進(jìn)行配置, android:largeheap = "true" 從而給APP申請(qǐng)更大的內(nèi)存空間。 有兩種溢出,堆溢出和棧溢出

內(nèi)存泄漏

指程序在申請(qǐng)內(nèi)存后,被某個(gè)對(duì)象一直持有,無(wú)法釋放已申請(qǐng)的內(nèi)存空間,一次內(nèi)存泄漏危害可以忽略, 但內(nèi)存泄漏堆積后果很嚴(yán)重,無(wú)論多少內(nèi)存,遲早會(huì)被占光。

2、 垃圾回收機(jī)制的原理是什么?

這里先寫(xiě)了一段代碼, 先看一下內(nèi)存是怎么存儲(chǔ)的

public class Fruit {

    static int x =10;
    static BigWaterMelon bigWaterMelon = new BigWaterMelon(x);
    int y = 20;
    BigWaterMelon bigWaterMelon_2 = new BigWaterMelon(y);
    public static void main(String[] args) {
        final Fruit fruit = new Fruit();
        int z = 30;
        BigWaterMelon bigWaterMelon_3 = new BigWaterMelon(z);

        new Thread(){
            @Override
            public void run() {
                super.run();
                int k = 100;
                setWeight(k);
            }

            void setWeight(int waterMelonWeight){
                fruit.bigWaterMelon_2.weight = waterMelonWeight;
            }
        }.start();
    }
}

class BigWaterMelon {
    public  int weight;
    public BigWaterMelon(int weight) {
        this.weight = weight;
    }
}

對(duì)應(yīng)的內(nèi)存里存儲(chǔ)的位置

image.png

GCRoot內(nèi)存結(jié)構(gòu)

image.png

1、JVM內(nèi)存劃分為堆內(nèi)存和非堆內(nèi)存,堆內(nèi)存分為年輕代和老年代,非堆內(nèi)存就一個(gè)永久代(方法區(qū))
2、 年輕代又分為Eden和Survivor區(qū)。Survivor區(qū)由FromSpace和ToSpace組成。Eden區(qū)占大容量,Survivor兩個(gè)區(qū)占小容量,默認(rèn)比例是8:1:1。
3、 堆內(nèi)存用途: 存放的是對(duì)象,垃圾收集器就是收集這些對(duì)象,然后根據(jù)GC算法回收。
4、 非堆內(nèi)存用途:永久代,也稱為方法區(qū),存儲(chǔ)程序運(yùn)行時(shí)長(zhǎng)期存活的對(duì)象,比如類的元數(shù)據(jù)、方法、常量、屬性等。

垃圾回收算法(標(biāo)記-清除)
1、 GC分為兩個(gè)階段,標(biāo)記和清除。首先標(biāo)記所有可回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象,同時(shí)會(huì)產(chǎn)生不連續(xù)的內(nèi)存碎片。
2、 碎片過(guò)多會(huì)導(dǎo)致以后程序運(yùn)行時(shí)需要分配較大對(duì)象時(shí),無(wú)法找到足夠的連續(xù)內(nèi)存,而不得已再次出發(fā)GC。
垃圾回收算法(標(biāo)記-整理)
1、 分為兩個(gè)階段,首先標(biāo)記可回收的對(duì)象 =
2、 再將存活的對(duì)象都向一端移動(dòng),然后清理掉邊界以外的內(nèi)存
3、此方法避免標(biāo)記-清除算法的碎片問(wèn)題,同時(shí)也避免了復(fù)制算法的空間問(wèn)題
4、 一般年輕代中執(zhí)行GC后,會(huì)有少量的對(duì)象存活,就會(huì)選用復(fù)制算法,只要付出少量的存活對(duì)象復(fù)制成本就可以完成收集
5、 而老年代中因?yàn)閷?duì)象存活率高,沒(méi)有額外過(guò)多內(nèi)存空間分配,就需要標(biāo)記-清理或者標(biāo)記-整理算法來(lái)進(jìn)行回收

3、 什么情況下會(huì)出現(xiàn)Android內(nèi)存泄漏(六大類)

1、單例的使用不當(dāng)導(dǎo)致內(nèi)存泄漏(因?yàn)閱卫撵o態(tài)特性使得它的生命周期同應(yīng)用的生命周期一樣長(zhǎng),如果一個(gè)對(duì)象已經(jīng)沒(méi)有用處了,但是單例還持有它的引用,那么在整個(gè)應(yīng)用程序的生命周期它都不能正常被回收,從而導(dǎo)致內(nèi)存泄漏);
2、靜態(tài)變量造成的內(nèi)存泄漏(靜態(tài)變量存儲(chǔ)在方法區(qū),它的生命周期從類加載開(kāi)始,到整個(gè)進(jìn)程結(jié)束。一旦靜態(tài)變量初始化后,它所持有的引用只有等到進(jìn)程結(jié)束才會(huì)釋放);
3、非靜態(tài)內(nèi)部類導(dǎo)致內(nèi)存泄漏(非靜態(tài)內(nèi)部類(包括匿名內(nèi)部類)默認(rèn)就會(huì)持有外部類的引用,當(dāng)非靜態(tài)內(nèi)部類對(duì)象的生命周期比外部類對(duì)象的生命周期長(zhǎng)時(shí),就會(huì)導(dǎo)致內(nèi)存泄漏 -> 軟引用/調(diào)成靜態(tài))
(常見(jiàn)的有:Handler,Thread,AsyncTask)
4、 未取消注冊(cè)或回調(diào)導(dǎo)致內(nèi)存泄漏(比如我們?cè)贏ctivity中注冊(cè)廣播,如果在Activity銷毀后不取消注冊(cè),那么這個(gè)廣播會(huì)一直存在系統(tǒng)中,同上面所說(shuō)的非靜態(tài)內(nèi)部類一樣持有Activity引用,導(dǎo)致內(nèi)存泄漏,因此注冊(cè)廣播后在Activity銷毀后一定要取消注冊(cè));
5、集合中的對(duì)象未清理造成內(nèi)存泄漏(在循環(huán)中把對(duì)象o引用釋放了,但它被添加到了objectList中,所以objectList也持有對(duì)象的引用,此時(shí)該對(duì)象是無(wú)法被GC的,因此對(duì)象如果添加到集合中,還必須從中刪除,最簡(jiǎn)單的方法防治集合類泄漏內(nèi)存的方法);
6、資源未關(guān)閉或釋放導(dǎo)致內(nèi)存泄漏(在使用流或者等資源時(shí)要及時(shí)關(guān)閉。這些資源在進(jìn)行讀寫(xiě)操作時(shí)通常都使用了緩沖,如果及時(shí)不關(guān)閉, 這些緩沖對(duì)象就會(huì)一直被占用而得不到釋放,以致發(fā)生內(nèi)存泄漏。因此我們?cè)诓恍枰褂盟鼈兊臅r(shí)候就及時(shí)關(guān)閉,以便緩沖能及時(shí)得到釋放,從而避免內(nèi)存泄漏);例如 webView下面持有Activity引用,造成了WebView內(nèi)存無(wú)法釋放,在onDestory方法里把webView給remove掉(在銷毀WebView之前需要先將WebView從父容器中移除,然后再銷毀WebView)

4、 什么是內(nèi)存抖動(dòng),造成的本質(zhì)是什么?(年輕堆與老年堆)

內(nèi)存抖動(dòng)

是指在短時(shí)間內(nèi)有大量的對(duì)象被創(chuàng)建或者被回收的現(xiàn)象。

內(nèi)存抖動(dòng)結(jié)果

如果抖動(dòng)很頻繁,會(huì)導(dǎo)致垃圾回收機(jī)制頻繁運(yùn)行(短時(shí)間內(nèi)產(chǎn)生大量對(duì)象,需要大量?jī)?nèi)存,而且還是頻繁抖動(dòng),就可能會(huì)需要回收內(nèi)存以用于產(chǎn)生對(duì)象,垃圾回收機(jī)制就自然會(huì)頻繁運(yùn)行了)
本質(zhì)就是頻繁的創(chuàng)建大量對(duì)象和使用垃圾回收機(jī)制
例如 :MotionEvent、Message

解決:

1、 盡量避免在循環(huán)體內(nèi)創(chuàng)建對(duì)象,應(yīng)該把對(duì)象創(chuàng)建移到循環(huán)體外
2、注意自定義View的onDraw()方法會(huì)被頻繁調(diào)用,所以在這里面不應(yīng)該頻繁的創(chuàng)建對(duì)象
3、 當(dāng)需要大量使用Bitmap的時(shí)候,試著把它們緩存在數(shù)組中實(shí)現(xiàn)復(fù)用
4、對(duì)于能夠復(fù)用的對(duì)象,同理可以使用對(duì)象池將它們緩存起來(lái)

5、 怎么處理Crash異常,對(duì)于不能定位行數(shù)的問(wèn)題怎么解決

crash異常分為兩種異常,
1、直接拋出exception,程序崩潰。分析日志
2、是OOM的問(wèn)題,無(wú)響應(yīng)。分析用戶的行為,讓測(cè)試去復(fù)現(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容