Android內(nèi)存泄漏 ——檢測(cè)、解決和避免

作為開(kāi)發(fā)人員翻斟,在我們的日常開(kāi)發(fā)中逾礁,為了構(gòu)建更好的應(yīng)用程序,我們需要考慮很多事情以保證應(yīng)用運(yùn)行在正軌上访惜,其中之一是要確保我們的應(yīng)用程序不會(huì)崩潰嘹履。應(yīng)用崩潰的一個(gè)常見(jiàn)原因是內(nèi)存泄漏。這方面的問(wèn)題可以以各種形式表現(xiàn)出來(lái)债热。在大多數(shù)情況下砾嫉,我們看到內(nèi)存使用率穩(wěn)步上升,直到應(yīng)用程序不能分配更多的資源窒篱,并不可避免地崩潰焕刮。在Java中這往往導(dǎo)致一個(gè)OutOfMemoryException異常被拋出舶沿。在某些罕見(jiàn)的情況下,泄露的類甚至可以逗留很長(zhǎng)時(shí)間來(lái)接收已注冊(cè)的回調(diào)配并,這會(huì)導(dǎo)致一些非常奇怪的錯(cuò)誤括荡,并往往拋出臭名昭著的IllegalStateException異常

為了幫助他人在代碼分析上減少花費(fèi)時(shí)間荐绝,我將介紹內(nèi)存泄漏的幾個(gè)例子,闡述在Android Studio中如何檢查它們避消,當(dāng)然最重要的是如何將其解決低滩。

聲明

在這篇文章中的代碼示例的目的是為了促進(jìn)大家對(duì)內(nèi)存管理有更深的了解,特別是在java岩喷。其通用的體系結(jié)構(gòu)恕沫,線程管理和代碼示例的 HTTP 請(qǐng)求處理在真實(shí)的生產(chǎn)環(huán)境并不是理想的,這些示例僅僅為了說(shuō)明一個(gè)問(wèn)題:在Android中纱意,內(nèi)存泄漏是一件要考慮的事情婶溯。

監(jiān)聽(tīng)器注冊(cè)

這真的不應(yīng)該是個(gè)問(wèn)題,但我經(jīng)惩得梗看到各種注冊(cè)方法的調(diào)用迄委,但他們對(duì)應(yīng)的注銷方法卻無(wú)處可尋。這是泄漏的潛在來(lái)源类少,因?yàn)檫@些方法明確設(shè)計(jì)成互相抵消叙身。如果沒(méi)有調(diào)用注銷方法,被引用的對(duì)象已經(jīng)被終止后硫狞,監(jiān)聽(tīng)實(shí)例可能會(huì)持有該對(duì)象很長(zhǎng)的時(shí)間信轿,從而導(dǎo)致泄漏內(nèi)存。在Android中残吩,如果該對(duì)象是一個(gè)Activity對(duì)象财忽,是特別麻煩的,因?yàn)樗麄兺鶕碛写罅康臄?shù)據(jù)泣侮。讓我告訴你即彪,可能是什么樣子。

public class LeaksActivity extends Activity implements LocationListener {

    private LocationManager locationManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leaks);
        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                TimeUnit.MINUTES.toMillis(5), 100, this);
    }

    // Listener implementation omitted
}

在這個(gè)例子中活尊,我們讓Android的 LocationManager通知我們位置更新祖凫。我們所需要做的就是獲取系統(tǒng)服務(wù)本身和設(shè)置一個(gè)回調(diào)來(lái)接收更新。在這里酬凳,我們?cè)贏ctivity中實(shí)現(xiàn)了位置監(jiān)聽(tīng)接口惠况,這意味著LocationManager將持有該Activity的引用。現(xiàn)在宁仔,如果該設(shè)備被旋轉(zhuǎn)稠屠,新的Activity將被創(chuàng)建并取代已經(jīng)注冊(cè)位置更新接口的舊的Activity。由于系統(tǒng)服務(wù)存活時(shí)間肯定比任何Activity都要長(zhǎng),LocationManager仍然持有以前的Activity的引用权埠,這使GC不可能回收依賴于以前的Activity的資源榨了,從而導(dǎo)致內(nèi)存泄漏。如果反復(fù)旋轉(zhuǎn)設(shè)備攘蔽,將導(dǎo)致大量的不可回收的Activity填滿內(nèi)存龙屉,最終導(dǎo)致OutOfMemoryException異常

但為了解決內(nèi)存泄漏满俗,我們首先必須要能夠找到它转捕。幸運(yùn)的是,Android Studio有一個(gè)叫做 Android Monitor的內(nèi)置工具唆垃,我們可以用它來(lái) 觀察除應(yīng)用內(nèi)存使用情況五芝。我們需要做的僅僅是打開(kāi)Android Monitor 并轉(zhuǎn)到對(duì)應(yīng)tab,看看使用了多少內(nèi)存和內(nèi)存實(shí)時(shí)分配情況辕万。

1-3R36AJUjtdBArkIxPuED3g.png

任何導(dǎo)致資源分配的交互都在這里反映出來(lái)枢步,使之成為跟蹤應(yīng)用程序的資源使用情況的理想場(chǎng)所。為了找到內(nèi)存泄露渐尿,當(dāng)我們懷疑在某個(gè)時(shí)間點(diǎn)內(nèi)存被泄露時(shí)醉途,我們需要知道在該時(shí)間點(diǎn)包含了那些內(nèi)存。對(duì)于這個(gè)特殊的例子砖茸,我們所要做的就是啟動(dòng)我們的應(yīng)用程序结蟋,然后旋轉(zhuǎn)設(shè)備一次,然后調(diào)用Dump Java Heap操作(在Memory的旁邊渔彰,從左邊數(shù)起第三個(gè)圖標(biāo))嵌屎。這將生成一個(gè)HPROF文件,其中包含我們調(diào)用該操作時(shí)的一個(gè)內(nèi)存快照恍涂。幾秒鐘后宝惰,Android Studio 會(huì)自動(dòng)打開(kāi)該文件,給我們更易于分析內(nèi)存的直觀表示再沧。

我不會(huì)去深入有關(guān)如何分析巨大的內(nèi)存堆尼夺。相反,我會(huì)把你的注意力引導(dǎo)到 Analyzer Tasks(下面截圖中的右上角)炒瘸。為了檢測(cè)上面的例子中引入的內(nèi)存泄漏淤堵,你所需要做的檢測(cè)是檢查泄露的Activity(Detect Leaked Activities),點(diǎn)擊播放按鈕然后在Analysis Results下面就會(huì)顯示泄露的Activity情況顷扩。

Paste_Image.png

如果我們選中泄露的Activity拐邪,可以得到一個(gè)引用樹(shù),該引用樹(shù)可以檢測(cè)持有該Activity的引用隘截。通過(guò)尋找深度為零的實(shí)例扎阶,我們發(fā)現(xiàn)位置管理器中的實(shí)例mListener汹胃,是我們的Activity不能被GC回收的原因《危回到我們的代碼着饥,我們可以看到,這個(gè)引用是由于我們?cè)?strong>requestLocationsUpdates方法中設(shè)置Activity作為位置更新回調(diào)導(dǎo)致的惰赋。通過(guò)閱讀位置管理器文檔宰掉,問(wèn)題很快變得清晰,為了取消回調(diào)設(shè)置赁濒,我們簡(jiǎn)單地調(diào)用removeUpdates方法就行了轨奄。在我們的例子,因?yàn)槲覀冏?cè)更新是在onCreate方法流部,顯然要注銷的地方在onDestroy方法戚绕。

public class LeaksActivity extends Activity implements LocationListener {

    private LocationManager locationManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leaks);
        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                TimeUnit.MINUTES.toMillis(5), 100, this);
    }

    @Override
    protected void onDestroy() {
        locationManager.removeUpdates(this);
        super.onDestroy();
    }

    // Listener implementation omitted
}

重新構(gòu)建程序并執(zhí)行與上述相同的內(nèi)存分析纹坐,無(wú)論旋轉(zhuǎn)多少次設(shè)備枝冀,應(yīng)該都不會(huì)導(dǎo)致Activity泄漏。

內(nèi)部類

內(nèi)部類在Java中是一個(gè)很常見(jiàn)的數(shù)據(jù)結(jié)構(gòu)耘子。它們很受歡迎果漾,因?yàn)樗鼈兛梢砸赃@樣的方式來(lái)定義:即只有外部類可以實(shí)例化它們。很多人可能沒(méi)有意識(shí)到的是這樣的類會(huì)持有外部類的隱式引用谷誓。隱式引用很容易出錯(cuò)绒障,尤其是當(dāng)兩個(gè)類具有不同的生命周期。以下是常見(jiàn)的Android Activity寫(xiě)法捍歪。

public class AsyncActivity extends Activity {

    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async);
        textView = (TextView) findViewById(R.id.textView);

        new BackgroundTask().execute();
    }

    private class BackgroundTask extends AsyncTask<Void, Void, String> {

        @Override
        protected String doInBackground(Void... params) {
            // Do background work. Code omitted.
            return "some string";
        }

        @Override
        protected void onPostExecute(String result) {
            textView.setText(result);
        }
    }
}

這種特殊的實(shí)現(xiàn)在執(zhí)行上沒(méi)有問(wèn)題户辱。問(wèn)題是,它保留內(nèi)存的時(shí)間肯定會(huì)超過(guò)必要的時(shí)間糙臼。由于BackgroundTask持有一個(gè)AsyncActivity隱式引用并運(yùn)行在另一個(gè)沒(méi)有取消策略的線程上庐镐,它將保留AsyncActivity在內(nèi)存中的所有資源連接,直到后臺(tái)線程終止運(yùn)行变逃。在HTTP請(qǐng)求的情況下必逆,這可能需要很長(zhǎng)的時(shí)間,尤其是在速度較慢的連接揽乱。

通過(guò)執(zhí)行相同的步驟名眉,如同前面的示例,并確保長(zhǎng)時(shí)間運(yùn)行的后臺(tái)任務(wù)凰棉,我們最終會(huì)得到下面的分析結(jié)果损拢。

Paste_Image.png

從上面的分析中可以看出,BackgroundTask 確實(shí)是這種內(nèi)存泄漏的罪魁禍?zhǔn)兹鱿N覀兊谝灰獎(jiǎng)?wù)是使用靜態(tài)類的實(shí)現(xiàn)方式來(lái)消除指向Activity的引用探橱,但這樣我們也不能直接訪問(wèn) textView 了申屹。因此我們還需要添加一個(gè)構(gòu)造函數(shù),把textView作為參數(shù)傳遞進(jìn)來(lái)隧膏。最后哗讥,我們需要引入AsyncTask文檔中所述的取消策略“恚考慮到所有這一切杆煞,讓我們看看我們的代碼最終呈現(xiàn)。

public class AsyncActivity extends Activity {

    TextView textView;
    AsyncTask task;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async);
        textView = (TextView) findViewById(R.id.textView);

        task = new BackgroundTask(textView).execute();
    }
    
    @Override
    protected void onDestroy() {
        task.cancel(true);
        super.onDestroy();
    }

    private static class BackgroundTask extends AsyncTask<Void, Void, String> {

        private final TextView resultTextView;

        public BackgroundTask(TextView resultTextView) {
            this.resultTextView = resultTextView;
        }
        
        @Override
        protected void onCancelled() {
            // Cancel task. Code omitted.
        }

        @Override
        protected String doInBackground(Void... params) {
            // Do background work. Code omitted.
            return "some string";
        }

        @Override
        protected void onPostExecute(String result) {
            resultTextView.setText(result);
        }
    }
}

現(xiàn)在腐泻,隱式引用已被消除决乎,我們通過(guò)構(gòu)造函數(shù)傳遞相關(guān)實(shí)例,并在合適的地方取消任務(wù)派桩。讓我們?cè)龠\(yùn)行分析任務(wù)构诚,看看這種改變是否消除了內(nèi)存泄漏。

Paste_Image.png

看來(lái)我們還有一些工作要做铆惑。根據(jù)前一個(gè)例子的經(jīng)驗(yàn)范嘱,我們可以知道在引用樹(shù)中高亮標(biāo)注的實(shí)例導(dǎo)致了Activity泄露。那么這是什么回事员魏?我們看一下它的父節(jié)點(diǎn)就可以發(fā)現(xiàn)resultTextView持有一個(gè)mContext引用丑蛤,毫無(wú)疑問(wèn),它就是泄露的Activity的引用撕阎。那么如何解決這個(gè)問(wèn)題受裹?我們無(wú)法消除resultTextView綁定的context引用,因?yàn)槲覀冃枰?strong>BackgroundTask中使用resultTextView的引用虏束,以便更新用戶界面棉饶。為了解決這個(gè)問(wèn)題,一種簡(jiǎn)單的方法是使用WeakReference镇匀。我們持有的resultTextView引用是強(qiáng)引用照藻,具有防止GC回收的能力。相反坑律,WeakReference不保證其引用的實(shí)例存活岩梳。當(dāng)一個(gè)實(shí)例最后一個(gè)強(qiáng)引用被刪除,GC會(huì)把其資源回收晃择,而不管這個(gè)實(shí)例是否有弱引用冀值。下面是使用WeakReference的最終版本:

public class AsyncActivity extends Activity {

    TextView textView;
    AsyncTask task;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async);
        textView = (TextView) findViewById(R.id.textView);

        task = new BackgroundTask(textView).execute();
    }
    
    @Override
    protected void onDestroy() {
        task.cancel(true);
        super.onDestroy();
    }

    private static class BackgroundTask extends AsyncTask<Void, Void, String> {

        private final WeakReference<TextView> textViewReference;

        public BackgroundTask(TextView resultTextView) {
            this.textViewReference = new WeakReference<>(resultTextView);
        }
        
        @Override
        protected void onCancelled() {
            // Cancel task. Code omitted.
        }

        @Override
        protected String doInBackground(Void... params) {
            // Do background work. Code omitted.
            return "some string";
        }

        @Override
        protected void onPostExecute(String result) {
            TextView view = textViewReference.get();
            if (view != null) {
                view.setText(result);
            }
        }
    }
}

請(qǐng)注意,在onPostExecute我們要檢查空值宫屠,判斷實(shí)例是否被回收列疗。

最后,再一次運(yùn)行分析器任務(wù)浪蹂,確認(rèn)我們的Activity不再被泄露 抵栈!

匿名類

這種類型的類和內(nèi)部類有同樣的缺點(diǎn)告材,即他們持有外部類的引用。如同內(nèi)部類古劲,一個(gè)匿名類在Activity生命周期之外執(zhí)行或在其他線程執(zhí)行工作時(shí)斥赋,可能會(huì)導(dǎo)致內(nèi)存泄漏。在這個(gè)例子中产艾,我將使用流行的HTTP請(qǐng)求庫(kù)Retrofit執(zhí)行API調(diào)用疤剑,并傳遞響應(yīng)給對(duì)應(yīng)回調(diào)。根據(jù)Retrofit homepage上面例子對(duì)Retrofit進(jìn)行配置闷堡。我會(huì)在Application中持有GitHubService引用隘膘,這不是一個(gè)特別好的設(shè)計(jì),這僅僅服務(wù)于這個(gè)例子的目的杠览。

public class ListenerActivity extends Activity {

    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_listener);
        textView = (TextView) findViewById(R.id.textView);

        GitHubService service = ((LeaksApplication) getApplication()).getService();
        service.listRepos("google")
                .enqueue(new Callback<List<Repo>>() {
                    @Override
                    public void onResponse(Call<List<Repo>> call,
                                           Response<List<Repo>> response) {
                        int numberOfRepos = response.body().size();
                        textView.setText(String.valueOf(numberOfRepos));
                    }

                    @Override
                    public void onFailure(Call<List<Repo>> call, Throwable t) {
                        // Code omitted.
                    }
                });
    }
}

這是常見(jiàn)的解決方案弯菊,不應(yīng)該導(dǎo)致任何泄漏。但是踱阿,如果我們?cè)诼龠B接中執(zhí)行這個(gè)例子管钳,分析結(jié)果會(huì)有所不同。請(qǐng)記住扫茅,直到該線程終止蹋嵌,該Activity會(huì)一直被持有育瓜,就像在內(nèi)部類的例子葫隙。

Paste_Image.png

根據(jù)在內(nèi)部類的例子中同樣的推理,我們得出一個(gè)結(jié)論:匿名回調(diào)類是內(nèi)存泄漏的原因躏仇。然而恋脚,正如內(nèi)部類的例子,此代碼包含兩個(gè)問(wèn)題焰手。首先糟描,請(qǐng)求沒(méi)有取消策略。其次书妻,需要消除對(duì)Activity的隱式引用船响。明顯的解決辦法:我們?cè)趦?nèi)部類的例子做了同樣的事情。

public class ListenerActivity extends Activity {

    TextView textView;
    Call call;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_listener);
        textView = (TextView) findViewById(R.id.textView);

        GitHubService service = ((LeaksApplication) getApplication()).getService();
        call = service.listRepos("google");
        call.enqueue(new RepoCallback(textView));
    }

    @Override
    protected void onDestroy() {
        call.cancel();
        super.onDestroy();
    }

    private static class RepoCallback implements Callback<List<Repo>> {

        private final WeakReference<TextView> resultTextView;

        public RepoCallback(TextView resultTextView) {
            this.resultTextView = new WeakReference<>(resultTextView);
        }

        @Override
        public void onResponse(Call<List<Repo>> call,
                Response<List<Repo>> response) {
            TextView view = resultTextView.get();
            if (view != null) {
                int numberOfRepos = response.body().size();
                view.setText(String.valueOf(numberOfRepos));
            }
        }

        @Override
        public void onFailure(Call<List<Repo>> call, Throwable t) {
            // Code omitted.
        }
    }
}

根據(jù)上述解決方案躲履,運(yùn)行分析任務(wù)见间,將不會(huì)再有Activity的泄露。

結(jié)論

后臺(tái)任務(wù)獨(dú)立于Activity的生命周期運(yùn)行是一件麻煩事工猜。再加上需要協(xié)調(diào)用戶界面和各種后臺(tái)任務(wù)之間的數(shù)據(jù)流米诉,如果你不小心,那將是一個(gè)災(zāi)難篷帅。所以要知道你在做什么史侣,以及你的代碼是否對(duì)性能有影響拴泌。這些基本準(zhǔn)則是處理Activity的良好開(kāi)端:

  • 盡量使用靜態(tài)內(nèi)部類。每個(gè)非靜態(tài)內(nèi)部類將持有一個(gè)外部類的隱式引用惊橱,這可能會(huì)導(dǎo)致不必要的問(wèn)題蚪腐。使用靜態(tài)內(nèi)部類代替非靜態(tài)內(nèi)部類,并通過(guò)弱引用存儲(chǔ)一些必要的生命周期引用税朴。
  • 考慮后臺(tái)服務(wù)等手段削茁, Android提供了多種在非主線程工作的方法,如HandlerThread掉房,IntentServiceAsyncTask茧跋,它們每個(gè)都有自己的優(yōu)缺點(diǎn)。另外卓囚,Android提供了一些機(jī)制來(lái)傳遞信息給主線程以更新UI瘾杭。譬如,廣播接收器就可以很方便實(shí)現(xiàn)這一點(diǎn)哪亿。
  • 不要一味依賴?yán)厥掌鳌?/strong>使用具有垃圾回收功能的語(yǔ)言編碼很容易有這樣的想法:即沒(méi)必要考慮內(nèi)存管理粥烁。我們的示例清楚地表明,并非如此蝇棉。因此讨阻,請(qǐng)確保你分配的資源都被預(yù)期回收。

原文鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末篡殷,一起剝皮案震驚了整個(gè)濱河市钝吮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌板辽,老刑警劉巖奇瘦,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異劲弦,居然都是意外死亡耳标,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門邑跪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)次坡,“玉大人,你說(shuō)我怎么就攤上這事画畅≡依牛” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵夜赵,是天一觀的道長(zhǎng)明棍。 經(jīng)常有香客問(wèn)我,道長(zhǎng)寇僧,這世上最難降的妖魔是什么摊腋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任沸版,我火速辦了婚禮,結(jié)果婚禮上兴蒸,老公的妹妹穿的比我還像新娘视粮。我一直安慰自己,他們只是感情好橙凳,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布蕾殴。 她就那樣靜靜地躺著,像睡著了一般岛啸。 火紅的嫁衣襯著肌膚如雪钓觉。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天坚踩,我揣著相機(jī)與錄音荡灾,去河邊找鬼。 笑死瞬铸,一個(gè)胖子當(dāng)著我的面吹牛批幌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嗓节,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼荧缘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拦宣?” 一聲冷哼從身側(cè)響起截粗,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恢着,沒(méi)想到半個(gè)月后桐愉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體财破,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掰派,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了左痢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片靡羡。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖俊性,靈堂內(nèi)的尸體忽然破棺而出略步,到底是詐尸還是另有隱情,我是刑警寧澤定页,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布趟薄,位于F島的核電站,受9級(jí)特大地震影響典徊,放射性物質(zhì)發(fā)生泄漏杭煎。R本人自食惡果不足惜恩够,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望羡铲。 院中可真熱鬧蜂桶,春花似錦、人聲如沸也切。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)雷恃。三九已至疆股,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間倒槐,已是汗流浹背押桃。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留导犹,地道東北人唱凯。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像谎痢,于是被迫代替她去往敵國(guó)和親磕昼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,515評(píng)論 25 707
  • 內(nèi)存管理的目的就是讓我們?cè)陂_(kāi)發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問(wèn)題节猿。內(nèi)存泄漏大家都不陌生了票从,簡(jiǎn)單粗俗的講,...
    宇宙只有巴掌大閱讀 2,360評(píng)論 0 12
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們?cè)陂_(kāi)發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問(wèn)題滨嘱。內(nèi)存泄漏...
    _痞子閱讀 1,625評(píng)論 0 8
  • LEON: 今天我們來(lái)上第五課峰鄙。 昨晚你說(shuō)看電影學(xué)英語(yǔ),真是快樂(lè)學(xué)英語(yǔ)太雨。說(shuō)得對(duì)吟榴,也不全對(duì)∧野猓看電影是學(xué)英語(yǔ)的一部分吩翻,...
    嶺南后生閱讀 461評(píng)論 2 0
  • 我在黑夜里潛行, 不見(jiàn)一絲的光亮锥咸。 月亮和星子也已安眠狭瞎, 不見(jiàn)一個(gè)出路。
    娑喬閱讀 316評(píng)論 0 0