Android—常見(jiàn)的內(nèi)存泄漏場(chǎng)景及解決方案

我的CSDN: ListerCi
我的簡(jiǎn)書(shū): 東方未曦

一、引言

一般情況下Android的內(nèi)存泄漏是因?yàn)椋嬖谝弥赶蛞粋€(gè)本該被回收的對(duì)象,例如已經(jīng)執(zhí)行onDestroy()的Activity。在這種情況下,由于Activity內(nèi)某些對(duì)象的生命周期比Activity要長(zhǎng),在Activity理論上被銷毀時(shí),該對(duì)象依舊存在并持有Activity的引用,因此內(nèi)存回收機(jī)制(GC)無(wú)法釋放Activity,最終導(dǎo)致內(nèi)存泄漏。

為了發(fā)現(xiàn)和修復(fù)APP中存在的內(nèi)存泄漏,開(kāi)發(fā)人員會(huì)在APP上安裝內(nèi)存檢測(cè)工具(如leakcanary),當(dāng)出現(xiàn)內(nèi)存泄漏時(shí),該工具會(huì)提供一個(gè)報(bào)告,里面包含了一條引用鏈,指明可能造成內(nèi)存泄漏的引用。開(kāi)發(fā)人員需要在合適的地方切斷引用鏈,以便GC釋放掉沒(méi)有被引用的對(duì)象。

有些內(nèi)存泄漏的修復(fù)很簡(jiǎn)單,將非靜態(tài)內(nèi)部類內(nèi)部類改為靜態(tài)內(nèi)部類或者將Context改為ApplicationContext后檢測(cè)工具就檢測(cè)不出內(nèi)存泄漏了,但是這到底是為什么呢?而且就算檢測(cè)工具檢測(cè)不出內(nèi)存泄漏,就真的萬(wàn)無(wú)一失了嗎?

帶著這些問(wèn)題,我們來(lái)分析一下Android常見(jiàn)的內(nèi)存泄漏場(chǎng)景以及解決方案。

二、Java內(nèi)存管理及垃圾回收機(jī)制

在了解Android的內(nèi)存泄漏之前,我們需要先了解Java的內(nèi)存管理以及垃圾回收機(jī)制。

2.1 內(nèi)存管理

Java的內(nèi)存分配區(qū)域主要分為以下幾個(gè)部分。

1. 靜態(tài)變量區(qū)

用于存儲(chǔ)被static修飾的靜態(tài)變量,這塊區(qū)域在程序開(kāi)始運(yùn)行時(shí)就已經(jīng)分配完畢,并且存在于程序的整個(gè)運(yùn)行過(guò)程。

2. 棧

主要用于分配局部變量,包括基本類型的變量和對(duì)象的引用變量,當(dāng)局部變量的作用域結(jié)束之后,Java會(huì)自動(dòng)釋放掉該變量占用的內(nèi)存空間。

3. 堆

堆是動(dòng)態(tài)內(nèi)存區(qū)域,程序運(yùn)行期間新建的對(duì)象實(shí)例和數(shù)組都存儲(chǔ)在堆中,垃圾回收機(jī)制(GC)管理的就是這塊內(nèi)存。為了及時(shí)地將不被使用的對(duì)象釋放掉,GC需要監(jiān)控每一個(gè)對(duì)象的狀態(tài),當(dāng)一個(gè)對(duì)象不再被引用時(shí),GC就會(huì)釋放該對(duì)象。

4. 常量池

常量池中的內(nèi)容在編譯時(shí)就已經(jīng)確定,主要包含代碼中的基本類型和對(duì)象類型的常量值。
例如,String就是對(duì)象類型,如果在編譯時(shí)確定了String的值(String s = "test"),那么它的值就存儲(chǔ)在常量池中,而它的引用存儲(chǔ)在棧中。如果String的值是在程序運(yùn)行時(shí)確定的(String s = new String("...")),那么它的值就存儲(chǔ)在堆中。

假設(shè)當(dāng)前有一個(gè)實(shí)例A存儲(chǔ)在堆中,我們定義了一個(gè)引用a指向?qū)嵗鼳。此時(shí)引用a其實(shí)是保存在棧中的,它的值為實(shí)例A在堆內(nèi)存中的首地址,此時(shí)程序就可以通過(guò)a讀寫(xiě)A的值。

2.2 垃圾回收機(jī)制

上面提到,當(dāng)一個(gè)對(duì)象不再被引用時(shí),GC就應(yīng)該將其回收。確實(shí)有一種引用計(jì)數(shù)法來(lái)判斷一個(gè)對(duì)象是否需要被釋放,當(dāng)該對(duì)象的引用計(jì)數(shù)為0時(shí)代表它需要被回收。但是如果存在兩個(gè)對(duì)象,沒(méi)有別的引用指向它們,但是它們互相引用,此時(shí)它們的引用計(jì)數(shù)都不為0,導(dǎo)致無(wú)法釋放,容易造成內(nèi)存泄漏。

目前主流的的方法是通過(guò)可達(dá)性分析來(lái)判斷一個(gè)對(duì)象是否需要被釋放。該算法的基本思路就是通過(guò)一些被稱為引用鏈(GC Roots)的對(duì)象作為起點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索走過(guò)的路徑被稱為(Reference Chain),當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連時(shí)(即從GC Roots節(jié)點(diǎn)到該節(jié)點(diǎn)不可達(dá)),則證明該對(duì)象是不可用的。

在Java中,可作為GC Root的對(duì)象包括以下幾種:

  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象
  • 方法區(qū)中類靜態(tài)屬性引用的對(duì)象
  • 方法區(qū)中常量引用的對(duì)象
  • 本地方法棧中JNI(即一般說(shuō)的Native方法)引用的對(duì)象

三、Android常見(jiàn)內(nèi)存泄漏場(chǎng)景

3.1 內(nèi)部類持有外部類引用造成的內(nèi)存泄漏

1. 非靜態(tài)內(nèi)部類

我們知道非靜態(tài)內(nèi)部類可以訪問(wèn)外部類的變量,它通過(guò)變量this$0隱式地持有外部類的引用,這個(gè)變量是編譯器為非靜態(tài)內(nèi)部類添加的,如果內(nèi)部類的生命周期超過(guò)外部類,則會(huì)引發(fā)內(nèi)存泄漏。

造成這種情況的具體原因很多,可能是多線程或者監(jiān)聽(tīng)器未反注冊(cè)。如果需要快速修復(fù),可以將內(nèi)部類改為static,但是static變量的生命周期與App相同,該變量不會(huì)被回收。因此最好是在出現(xiàn)內(nèi)存泄漏時(shí),通過(guò)引用鏈尋找可以切斷的地方。后文的監(jiān)聽(tīng)器和Handler都屬于這種情況。

2. 匿名內(nèi)部類

匿名內(nèi)部類引發(fā)內(nèi)存泄漏的原因與非靜態(tài)內(nèi)部類相似,匿名內(nèi)部類通過(guò)xxx$1.class持有了外部類的引用,如果匿名內(nèi)部類的生命周期超過(guò)外部類,在外部類例如Activity銷毀時(shí),內(nèi)部類依舊持有外部類的引用,就會(huì)引發(fā)內(nèi)存泄漏。

如果像下面這樣直接在匿名內(nèi)部類中使用Runnable或者Handler時(shí)就非常容易引起內(nèi)存泄漏。由于Runnable執(zhí)行的時(shí)間很可能超過(guò)Activity,Activity在onDestroy()后匿名內(nèi)部類依舊存在,最終導(dǎo)致Activity泄露。

button.setOnClickListener(new View.OnClickListener() {
    @override
    public void onClick(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // ......
            }
       }).start();
    }
});

匿名內(nèi)部類引發(fā)的內(nèi)存泄漏不易修改,因?yàn)闆](méi)有辦法獲得該對(duì)象的引用,也就無(wú)法在Activity被銷毀時(shí)通過(guò)引用清除這些資源。因此對(duì)于可能引發(fā)內(nèi)存泄漏的匿名內(nèi)部類來(lái)說(shuō),應(yīng)該改為內(nèi)部類實(shí)現(xiàn)。

3.2 多線程造成的內(nèi)存泄漏

1. Runnable(Thread)

當(dāng)異步線程持有外部Activity的引用時(shí),如果Activity銷毀時(shí)線程還沒(méi)有執(zhí)行完,就會(huì)導(dǎo)致內(nèi)存泄漏。
解決辦法很簡(jiǎn)單,只需要在Activity銷毀之前終止線程即可。

2. AsyncTask

AsyncTaskHandler+Thread的封裝,用于完成異步任務(wù)。我們?cè)谑褂脮r(shí),一般繼承AsyncTask并重寫(xiě)doInBackground()方法和onPostExecute()方法,doInBackground()方法進(jìn)行耗時(shí)操作,onPostExecute()方法在主線程更新UI。
其常見(jiàn)的內(nèi)存泄漏原因與Runnable類似,也是由于AsyncTask未執(zhí)行完時(shí)Activity被銷毀,而AsyncTask又持有Activity的引用,導(dǎo)致Activity無(wú)法釋放,引起內(nèi)存泄漏。

對(duì)于AsyncTask造成的內(nèi)存泄漏,推薦使用cancel+isCancelled來(lái)解決。
如果一個(gè)任務(wù)沒(méi)有被執(zhí)行并且cancel方法被調(diào)用,那么任務(wù)會(huì)立即取消且不會(huì)被執(zhí)行。對(duì)于已經(jīng)在執(zhí)行的任務(wù),cancel方法只能保證其onPostExecute()不會(huì)被執(zhí)行,也就是說(shuō),即使調(diào)用了cancel方法,任務(wù)也不會(huì)立即停止,需要等待doInBackground()方法完成。cancel方法不會(huì)終止一個(gè)正在運(yùn)行的線程,只是給它設(shè)置cancelled狀態(tài),通知該線程應(yīng)該中斷了。
因此給任務(wù)調(diào)用cancel方法后還要檢查當(dāng)前task的狀態(tài),保證其及時(shí)退出。

@Override
protected Integer doInBackground(Void... args) {
    // Task被取消了,馬上退出
    if(isCancelled()) return null;
    .......
    // Task被取消了,馬上退出
    if(isCancelled()) return null;
}

雖然有這樣的解決辦法,但是對(duì)于異步操作,這里更推薦RxJava。

3.3 視圖造成的內(nèi)存泄漏

1. WebView

在進(jìn)行混合開(kāi)發(fā)時(shí),經(jīng)常需要在Activity中嵌入WebView來(lái)訪問(wèn)前端頁(yè)面,此時(shí)需要注意WebView的創(chuàng)建和回收問(wèn)題。
在Activity中使用WebView時(shí),推薦使用動(dòng)態(tài)創(chuàng)建和回收的方式進(jìn)行管理。在布局文件中定義一個(gè)ViewGroup,然后動(dòng)態(tài)地將WebView添加到ViewGroup中。

@override
protected void onCreate(Bundle savedInstanceState) {
    mWebView = new WebView(this);
    // WebView settings
    mWebView.setWebViewClient(...);
    mWebView.setWebChromeClient(...);
    // 將 WebView 添加到布局中的 ViewGroup 中
    FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    mWebViewLayout.addView(mWebView, layoutParams);
}

之后在Activity的onDestroy()方法中回收WebView相關(guān)資源。由于WebView內(nèi)部存在component callbacks,該回調(diào)在onAttachedToWindow()方法中進(jìn)行注冊(cè),并在onDetachedFromWindow()方法中進(jìn)行反注冊(cè)。為了順利反注冊(cè)該回調(diào),需要在WebView執(zhí)行destroy()之前將其從布局上移除。(具體見(jiàn)下方的參考2)

@override
protected void onDestroy() {
    // 從父容器移除 WebView 后再將其銷毀
    if (mWebView != null) {
        mWebView.loadDataWithBaseURL(
                null, "", "text/html", "utf-8", "");
        mWebView.clearHistory();
        mWebView.setWebViewClient(null);
        mWebView.setWebChromeClient(null);       
        mWebViewLayout.removeView(mWebView);
        mWebView.destroy();
        mWebView = null;
    }
}
2. static view

如果某個(gè)View在初始化時(shí)需要消耗大量資源,并且要求其在Activity生命周期中不變,就可能將其修飾為static加載到視圖樹(shù)上。由于View在新建時(shí)就持有Activity的引用,因此Activity銷毀時(shí)需要釋放資源。

public View(Context context) {
    mContext = context; // 此時(shí)View已經(jīng)持有Activity的引用
    // ......
}

面對(duì)這種情況,最好是將View設(shè)置為普通變量,可以避免這類內(nèi)存泄漏。

3.4 廣播、監(jiān)聽(tīng)器等未反注冊(cè)

這一類的內(nèi)存泄漏主要與觀察者模式有關(guān),一般情況下是有多個(gè)觀察者(Observer)對(duì)同一個(gè)被觀察者(Observable)進(jìn)行監(jiān)聽(tīng)。
如果有一個(gè)Manager對(duì)觀察者進(jìn)行統(tǒng)一管理的話,那么觀察者的對(duì)被觀察者監(jiān)聽(tīng)的注冊(cè)反注冊(cè)一定是成對(duì)出現(xiàn)的,不然就會(huì)出現(xiàn)內(nèi)存泄漏。在監(jiān)聽(tīng)器一節(jié)中會(huì)詳細(xì)描述這種場(chǎng)景。

1. 廣播

廣播的主要流程如下:

1:廣播接收者BroadcastReceiver通過(guò)Binder機(jī)制向AMS(Activity Manager Service)進(jìn)行注冊(cè)
2:廣播發(fā)送者通過(guò)binder機(jī)制向AMS發(fā)送廣播
3:AMS查找符合相應(yīng)條件(IntentFilter/Permission等)的BroadcastReceiver,將廣播發(fā)送到BroadcastReceiver(一般情況下是Activity)相應(yīng)的消息循環(huán)隊(duì)列中
4:消息循環(huán)執(zhí)行拿到此廣播,回調(diào)BroadcastReceiver中的onReceive()方法

根據(jù)上述流程,Activity在銷毀之前應(yīng)及時(shí)反注冊(cè),否則廣播管理者會(huì)一直保留當(dāng)前Activity的引用,而廣播管理者的生命周期是整個(gè)Application,最終會(huì)導(dǎo)致內(nèi)存泄漏。

2. 監(jiān)聽(tīng)器

上面提過(guò),如果存在一個(gè)統(tǒng)一的Manager對(duì)監(jiān)聽(tīng)器進(jìn)行管理的話,注冊(cè)和反注冊(cè)一定要成對(duì)出現(xiàn),否則很容易出現(xiàn)內(nèi)存泄漏的情況。下面來(lái)分析該場(chǎng)景。

假設(shè)當(dāng)前存在一個(gè)監(jiān)聽(tīng)器如下所示。

public interface MyListener {
    void run(...);
}

定義一個(gè)ListenerManager來(lái)對(duì)所有的監(jiān)聽(tīng)器進(jìn)行管理。

public class ListenerManager {
    // 單例模式
    private static final INSTANCE = new ListenerManager();
    // 存儲(chǔ)所有的監(jiān)聽(tīng)器
    private List<MyListener> mListeners = new CopyOnWriteArrayList<>();

    public static ListenerManager getInstance() {
        return INSTANCE;
    }

    // 注冊(cè)監(jiān)聽(tīng)器時(shí)將該監(jiān)聽(tīng)器添加到列表中
    public void registerListener(MyListener listener) {
        if (listener == null) return;
        if (mListeners.contains(listener)) return;
        mListeners.add(listener);
    }

    // 反注冊(cè)時(shí)將該監(jiān)聽(tīng)器從列表中移除
    public void unRegisterListener(MyListener listener) {
        if (listener == null) return false;
        return mListeners.remove(listener);
    }

    public void run() {
        for (MyListener listener : mListeners) {
            listener.run(...);
        }
    }
}

在使用到該監(jiān)聽(tīng)的Activity中添加如下代碼。

public class TestActivity {
    private TestListener mTestListener;

    @override
    protected void onCreate(...) {
        // ...
        mTestListener = new TestListener();
        ListenerManager.getInstance().registerListener(mTestListener);
    }

    @override
    protected void onDestroy() {
        // ...
        ListenerManager.getInstance().unRegisterListener(mTestListener);
    }

    private class TestListener implements MyListener {
        @override
        void run(...) {
            // ...
        }
    }
}

可以看到,在Activity中使用了內(nèi)部類的形式定義了監(jiān)聽(tīng)器,隨后在onCreate()方法中注冊(cè),并在onDestroy()中反注冊(cè)。那么如果沒(méi)有反注冊(cè)會(huì)出現(xiàn)什么情況呢?

首先ListenerManager的生命周期比Activity要長(zhǎng),如果Activity未進(jìn)行反注冊(cè),ListenerManager中的mListeners會(huì)一直持有TestListener對(duì)象的引用,又因?yàn)?code>TestListener是內(nèi)部類,它持有Activity的引用。
最終形成了ListenerManager->mListeners->mTestListener->Activity的引用鏈,導(dǎo)致Activity無(wú)法被釋放,形成了內(nèi)存泄漏。

3.5 其余情況

1. Handler

Handler作為Android的一種消息機(jī)制,通過(guò)HandlerMessageMessageQueueLooper四個(gè)類協(xié)調(diào)合作完成通信任務(wù)。
其中,Message是消息實(shí)體,包含硬件消息和軟件消息;
MessageQueue是消息隊(duì)列,主要的功能是向消息池投遞消息和取走消息池的消息;
Handler是輔助類,主要功能是向消息池發(fā)送消息事件(Handler.sendMessage())和處理相應(yīng)消息事件(Handler.handleMessage());
Looper是循環(huán)機(jī)制,不斷循環(huán)執(zhí)行將消息分發(fā)給目標(biāo)處理者。

如果我們?cè)贏ctivity中創(chuàng)建非靜態(tài)的Handler實(shí)例并重寫(xiě)handleMessage()方法,此時(shí)Handler隱式持有外部Activity的引用,而MessageQueue會(huì)持有Message引用,Message又持有Handler引用(Message需要知道自己會(huì)被發(fā)往哪個(gè)Handler)。
也就是說(shuō),如果Message不被消費(fèi),Activity就不會(huì)被釋放,如果使用postDelayed,在信息被消費(fèi)前關(guān)閉了Activity,就會(huì)造成內(nèi)存泄漏。

面對(duì)這種情況,最好是在Activity執(zhí)行onDestroy()時(shí)調(diào)用HandlerremoveCallbacksAndMessages清除所有信息;也可以選擇將Handler定義為靜態(tài)內(nèi)部類,這樣就不會(huì)持有外部Activity的引用了。

2. 資源未關(guān)閉

資源性對(duì)象(比如Cursor、File等)往往都做了一些緩沖,應(yīng)該在Activity銷毀時(shí)及時(shí)關(guān)閉或者注銷,否則這些資源將不會(huì)被回收,造成內(nèi)存泄漏。

3. 工具類生命周期問(wèn)題

有時(shí)代碼中會(huì)新建工具類用于完成一系列相同的操作,某些工具類在新建時(shí)需要傳入Context,如下所示。

public class Utils {
    private Context mContext;
    public Utils(Context context) {
        mContext = context;
    }
}

有時(shí)候工具類對(duì)象是在Activity內(nèi)部新建的,它的生命周期與Activity的生命周期相同,那么即使它持有context也不會(huì)引發(fā)內(nèi)存泄漏問(wèn)題。但是如果工具類的生命周期比Activity長(zhǎng)(如單例),那么傳入了哪個(gè)Activity的context,哪個(gè)Activity就會(huì)泄露。
正確的做法是使用ApplicationContext代替Context,使得工具類的生命周期與APP相同,就不會(huì)引發(fā)Activity的內(nèi)存泄露。

不過(guò)如果該工具類只在某幾個(gè)場(chǎng)景下用到呢?如果它的生命周期還是整個(gè)APP,雖然沒(méi)有內(nèi)存泄漏,但也是浪費(fèi)了一部分內(nèi)存。這時(shí)候就需要開(kāi)發(fā)人員對(duì)工具類的生命周期進(jìn)行管理,可以選擇在合適的時(shí)候清除該工具類對(duì)象。

四、參考

  1. 公司大佬筆記
  2. WebView內(nèi)存泄漏--解決方法小結(jié)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,560評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,035評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,814評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,224評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,444評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,804評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,998評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評(píng)論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,237評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,665評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,927評(píng)論 1 287
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,706評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,993評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • 一.什么是內(nèi)存泄漏 在Java程序中,如果一個(gè)對(duì)象沒(méi)有利用價(jià)值了,正常情況下gc是會(huì)對(duì)其進(jìn)行回收的,但是此時(shí)仍然有...
    l_genius閱讀 1,531評(píng)論 0 3
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們?cè)陂_(kāi)發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問(wèn)題。內(nèi)存泄漏...
    _痞子閱讀 1,648評(píng)論 0 8
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們?cè)陂_(kāi)發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問(wèn)題。內(nèi)存泄漏...
    神奇的小蘑菇閱讀 539評(píng)論 0 0
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們?cè)陂_(kāi)發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問(wèn)題。內(nèi)存泄漏...
    apkcore閱讀 1,232評(píng)論 2 7
  • 內(nèi)存管理的目的就是讓我們?cè)陂_(kāi)發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問(wèn)題。內(nèi)存泄漏大家都不陌生了,簡(jiǎn)單粗俗的講,...
    DreamFish閱讀 798評(píng)論 0 5