安卓OOM和Bitmap圖片二級緩存機(jī)制(一)

本文出自 “阿敏其人” 簡書博客,轉(zhuǎn)載或引用請注明出處夭坪。

OOM(Out Of Memory)

什么是OOM

手機(jī)系統(tǒng)內(nèi)存份存儲內(nèi)存(ROM)和運(yùn)行內(nèi)存(RAM),我們談?wù)揙OM討論的是運(yùn)行內(nèi)存,這點(diǎn)如果是新人需要明確询枚。≌阄祝現(xiàn)在一般來說手機(jī)運(yùn)行內(nèi)存是2G金蜀,3G基本就算很頂配了,4G運(yùn)行內(nèi)存的話只有個別手機(jī)配置了的畴。

簡而言之渊抄,OOM就是我們申請的內(nèi)存太大了,超出了系統(tǒng)分配給我們(app或者說進(jìn)程)的可用內(nèi)存丧裁。

android系統(tǒng)的app的每個進(jìn)程或者每個虛擬機(jī)有個最大內(nèi)存限制护桦,如果申請的內(nèi)存資源超過這個限制,系統(tǒng)就會拋出OOM錯誤煎娇。跟整個設(shè)備的剩余內(nèi)存沒太大關(guān)系二庵。比如比較早的android系統(tǒng)的一個虛擬機(jī)最多16M內(nèi)存,當(dāng)一個app啟動后缓呛,虛擬機(jī)不停的申請內(nèi)存資源來裝載圖片催享,當(dāng)超過內(nèi)存上限時就出現(xiàn)OOM。

舉個栗子.png

舉個栗子哟绊,一條金魚因妙,每次只能吃24顆飼料,你偏偏要喂它30顆票髓,結(jié)果攀涵,金魚受不鳥,就掛掉了洽沟。

安卓手機(jī)有多少內(nèi)存

早期的手機(jī)是每個進(jìn)程(每個app)分配16M以故。
后來隨著慢慢發(fā)展,開始有了24M的裆操,32M的怒详,再變態(tài)就是64了鳄乏。
具體每個手機(jī)的給app分配的運(yùn)行內(nèi)存根據(jù)廠商和機(jī)型的不同而定,但是基本的幾個數(shù)值是一樣的棘利。

安卓手機(jī)基于Linux系統(tǒng)橱野,Linux是一個多用戶的操作系統(tǒng),一個app在安卓手機(jī)里面就是一個用戶善玫,一個用戶分配到了16m(假如是16m水援,那么統(tǒng)一每一個app就是16m),當(dāng)我當(dāng)前這個app掛了茅郎,不會影響我其他程序的運(yùn)行蜗元。
比如我的手機(jī)里面有10個app,其中3個在運(yùn)行系冗,那么這個手機(jī)就有3個進(jìn)程在運(yùn)行奕扣,這3個進(jìn)程每一個都分配到了(16m)的運(yùn)行內(nèi)存。

每個App的內(nèi)存怎么分配

我是一個app掌敬,我被啟動了惯豆,我分配到了16m的空間,而且奔害,這16m還不是完完整整給你當(dāng)前程序自己玩?zhèn)€夠的楷兽,有一部分還必須分給native內(nèi)存。

  • 那么每一個程序的分配到的運(yùn)行內(nèi)存到底是怎么分配的呢华临?

16M = dalvik內(nèi)存(Java) + native內(nèi)存(C/C++)
APP內(nèi)存由 dalvik內(nèi)存 和 native內(nèi)存 2部分組成芯杀,dalvik也就是java堆,創(chuàng)建的對象就是就是在這里分配的雅潭,而native是通過c/c++方式申請的內(nèi)存揭厚,Bitmap就是以這種方式分配的。(android3.0以后扶供,系統(tǒng)都默認(rèn)通過dalvik分配的筛圆,native作為堆來管理)。這2部分加起來不能超過android對單個進(jìn)程诚欠,虛擬機(jī)的內(nèi)存限制顽染。

至于這Dvlyik和Native兩部分的分配,有個特點(diǎn)值得說一下轰绵。那就是Dalvik(Java)申請的內(nèi)存即使釋放了,native也別想去申請尼荆,只能Dalvik自己用左腔,Dalivk申請過的內(nèi)存Native就不能用了。

以下為引用部分

基于Android開發(fā)多媒體和游戲應(yīng)用時捅儒,可能會挺經(jīng)常出現(xiàn)Out Of Memory 異常 液样,顧名思義這個異常是說你的內(nèi)存不夠用或者耗盡了振亮。
在Android中,一個Process 只能使用16M內(nèi)存鞭莽,如果超過了這個限制就會跳出這個異常坊秸。這樣就要求我們要時刻想著釋放資源。Java的回收工作是交給GC的澎怒,如何讓GC能及時的回收已經(jīng)不是用的對象褒搔,這個里面有很多技巧,大家可以google一下喷面。
因?yàn)榭們?nèi)存的使用超過16M而導(dǎo)致OOM的情況星瘾,非常簡單,我就不繼續(xù)展開說惧辈。值得注意的是Bitmap在不用時琳状,一定要recycle,不然OOM是非常容易出現(xiàn)的盒齿。
本文想跟大家一起討論的是另一種情況:明明還有很多內(nèi)存念逞,但是發(fā)生OOM了。
這種情況經(jīng)常出現(xiàn)在生成Bitmap的時候边翁。有興趣的可以試一下肮柜,在一個函數(shù)里生成一個13m 的int數(shù)組。
再該函數(shù)結(jié)束后倒彰,按理說這個int數(shù)組應(yīng)該已經(jīng)被釋放了审洞,或者說可以釋放,這個13M的空間應(yīng)該可以空出來待讳,
這個時候如果你繼續(xù)生成一個10M的int數(shù)組是沒有問題的芒澜,反而生成一個4M的Bitmap就會跳出OOM。這個就奇怪了创淡,為什么10M的int夠空間痴晦,反而4M的Bitmap不夠呢?
這個問題困擾很久琳彩,在網(wǎng)上誊酌,國外各大論壇搜索了很久,一般關(guān)于OOM的解釋和解決方法都是露乏,如何讓GC盡快回收的代碼風(fēng)格之類碧浊,并沒有實(shí)際的支出上述情況的根源。
直到昨天在一個老外的blog上終于看到了這方面的解釋瘟仿,我理解后歸納如下:
在Android中:
1.一個進(jìn)程的內(nèi)存可以由2個部分組成:java 使用內(nèi)存 箱锐,C 使用內(nèi)存 ,這兩個內(nèi)存的和必須小于16M劳较,不然就會出現(xiàn)大家熟悉的OOM驹止,這個就是第一種OOM的情況浩聋。
2.更加奇怪的是這個:一旦內(nèi)存分配給Java后,以后這塊內(nèi)存即使釋放后臊恋,也只能給Java的使用衣洁,這個估計(jì)跟java虛擬機(jī)里把內(nèi)存分成好幾塊進(jìn)行緩存的原因有關(guān),反正C就別想用到這塊的內(nèi)存了抖仅,所以如果Java突然占用了一個大塊內(nèi)存坊夫,即使很快釋放了:
C能使用的內(nèi)存 = 16M - Java某一瞬間占用的最大內(nèi)存。
而Bitmap的生成是通過malloc進(jìn)行內(nèi)存分配的岸售,占用的是C的內(nèi)存践樱,這個也就說明了,上述的4MBitmap無法生成的原因凸丸,因?yàn)樵?3M被Java用過后拷邢,剩下C能用的只有3M了。

引用至此結(jié)束
點(diǎn)此查看原文地址

引用這一部分的描述屎慢,就是為了進(jìn)一步證明瞭稼,每個app所占用的16m(比如說16m)運(yùn)行內(nèi)存不是自己可以玩?zhèn)€夠的,還得和另外一個小伙伴分享

另外清楚一點(diǎn)腻惠,1环肘、我們在Bitmap的時候申請的內(nèi)存是輸入C/C++的,也就是Native這一塊的

OOM一般在什么時候發(fā)生集灌?

造成OOM的可以概括為兩種情況:
1悔雹、Bitmap的使用上 (利用Lru的LruCache和DiskLruCache兩個類來解決)
2、線程的管理上(利用線程池管理解決欣喧。不納入本次探討)

Bitmap導(dǎo)致的OOM是比較常見的腌零,而針對Bitmap,常見的有兩種情況:

  • 單個ImageView加載高清大圖的時候
  • ListView或者GridView等批量快速加載圖片的時候
    簡而言之唆阿,幾乎都是操作Bitmap的時候發(fā)生的益涧。

制造一個OOM的例子

當(dāng)前環(huán)境:

  • Android Studio1.4
  • win7 64bit
  • 模擬器: Genymotion Nexus One 2.3.7 API10 480*800

如何獲得當(dāng)前手機(jī)把為每個app(進(jìn)程)分配的運(yùn)行內(nèi)存

// 測試每個app可用的最大內(nèi)存(安卓每一個app都運(yùn)行在自己獨(dú)立的沙箱里面)
ActivityManager activityManager=(ActivityManager)MainActivity.this.getSystemService(Context.ACTIVITY_SERVICE);
int memoryClass = activityManager.getMemoryClass();// 返回的就是本機(jī)給每個app分配的運(yùn)行內(nèi)存      

當(dāng)我們當(dāng)前測模擬器返回的 32M 的運(yùn)行內(nèi)存

加載圖片

在此附上相關(guān)代碼:

public class MainActivity extends Activity implements View.OnClickListener {

    private TextView mTvBtn;  // 按鈕
    private TextView mTvNum;  // 顯示最大內(nèi)存
    private TextView mTvLoadBigPic;  // 加載圖片按鈕
    private ImageView  mIvPic;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        initView();

    }

    private void initView() {
        mTvBtn= (TextView) findViewById(R.id.mTvBtn);
        mTvNum= (TextView) findViewById(R.id.mTvNum);
        mTvLoadBigPic= (TextView) findViewById(R.id.mTvLoadBigPic);
        mIvPic= (ImageView) findViewById(R.id.mIvPic);

        mTvBtn.setOnClickListener(this);

        mTvLoadBigPic.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.mTvBtn:
                // 測試每個app可用的最大內(nèi)存(安卓每一個app都運(yùn)行在自己獨(dú)立的沙箱里面)
                ActivityManager activityManager =(ActivityManager)MainActivity.this.getSystemService(Context.ACTIVITY_SERVICE);
                int memoryClass = activityManager.getMemoryClass();// 返回的就是本機(jī)給每個app分配的運(yùn)行內(nèi)存
                mTvNum.setText("最大內(nèi)存: "+memoryClass);
                break;

            case R.id.mTvLoadBigPic:
                Bitmap bigPicBitMap=BitmapFactory.decodeResource(getResources(),R.mipmap.test_pic);
                mIvPic.setImageBitmap(bigPicBitMap);
                break;
        }
    }
}

看完代碼,我們這里應(yīng)該停下來看看一下Bitmap類驯鳖,補(bǔ)充一些知識

通過這樣的代碼就可以首先從資源文件里面加載圖片

Bitmap bigPicBitMap=BitmapFactory.decodeResource(getResources(),R.mipmap.test_pic);
mIvPic.setImageBitmap(bigPicBitMap); 

關(guān)于Bitmap和BitmapFactory的知識可以百度補(bǔ)充
提一下闲询,BitmapFactory提供了4類方法用于加載Bitmap對象

  • 1、decodeFile
  • 2浅辙、decodeResource
  • 3扭弧、decodeStream
  • 4、decodeByteArray
    分別從文件系統(tǒng)摔握、資源寄狼、輸入流和字節(jié)數(shù)組讀取Bitmap對象
    其中,decodeFile和decodeResource又間接調(diào)用了decodeStream方法氨淌,這四類方法都是在安卓底層實(shí)現(xiàn)的泊愧,對應(yīng)BitmapFactory類的幾個Native類。

decodeResource這個方法內(nèi)應(yīng)說到底還是需要創(chuàng)建一個位圖(Bitmap)盛正,
對于創(chuàng)建位圖删咱,我們來補(bǔ)充一個知識,先看一下的下面這個方法:

public static Bitmap createBitmap (int[] colors, int width, int height, Bitmap.Config config) 

具體安卓內(nèi)部如何調(diào)用這個方法本人不得而知豪筝,但是我們要明白的是 config 這個參數(shù)痰滋,每一個位圖都有一個默認(rèn)confit參數(shù),默認(rèn)值是 ARGB8888
對于config续崖,有幾個值敲街,我們借用一個文章說明一下:

A:透明度
R:紅色
G:綠
B:藍(lán)
Bitmap.Config ARGB_4444:由4個4位組成,即A=4严望,R=4多艇,G=4,B=4像吻,那么一個像素點(diǎn)占4+4+4+4=16位
Bitmap.Config ARGB_8888:由4個8位組成峻黍,即A=8,R=8拨匆,G=8姆涩,B=8,那么一個像素點(diǎn)占8+8+8+8=32位
Bitmap.Config RGB_565:即R=5惭每,G=6骨饿,B=5,沒有透明度台腥,那么一個像素點(diǎn)占5+6+5=16位
Bitmap.Config ALPHA_8:只有透明度宏赘,沒有顏色,那么一個像素點(diǎn)占8位览爵。
一般情況下我們都是使用的ARGB_8888置鼻,由此可知它是最占內(nèi)存的,因?yàn)橐粋€像素占32位蜓竹,8位=1字節(jié)(byte)箕母,所以一個像素占4字節(jié)的內(nèi)存。假設(shè)有一張480x800的圖片俱济,如果格式為ARGB_8888嘶是,那么將會占用(480x800x32)/(8x1024) = 1500KB的內(nèi)存。

簡單來說蛛碌,我們可以知道聂喇,Bitmap默認(rèn)的ARGB8888是一個質(zhì)量較好參數(shù),畢竟一個像素點(diǎn)有32個比特位(bit),相當(dāng)于4個字節(jié)(Byte)了希太。

夢回唐朝克饶,接著說OOM的例子

有了Bitmap和config的知識之后,我們的OOM的成功與否就看我們圖片的分辨率了

加入說誊辉,圖片分辨率是2500+1000矾湃,那么加載這張圖片所需要的運(yùn)行內(nèi)存我們可以大概這么算:
Bitmap.Config ARGB_8888情況下,一個像素點(diǎn)占32位堕澄,也就是4個字節(jié)邀跃。
2500 * 1000 * 4 得出多少個byte
(2500 * 1000) / 1024 得出kb
(2500 * 1000) / 1024 / 1024 得出m
經(jīng)過運(yùn)算,得出加載所需的運(yùn)行內(nèi)存大致為9.5m

是不是說我們當(dāng)前手機(jī)的這個app就一定可以加載這張圖片呢蛙紫?
不一定拍屑,如果這個時候app還有其他代碼也占用著的內(nèi)存,可能就加載不了了坑傅。而且我們說過僵驰,分配到的16m內(nèi)存不是自己玩?zhèn)€夠,還得兩個哥們分著玩裁蚁。
如果想一針見血矢渊,徹底減小,可以整個5000*2000的圖片枉证,肯定馬上掛掉矮男,爆出OOM。
5000 * 2000 * 4 / 1024 / 1024 得出 38m多室谚。一針見血


高效加載大圖和二級緩存毡鉴,避免OOM

知道了OOM是什么,怎么發(fā)生的秒赤,接下來我們就應(yīng)該知道怎么解決問題了猪瞬。
提出的問題的人很多铺厨,拿出解決辦法才是關(guān)鍵太颤。

如何高效加載大圖?

造成OOM的核心原因:圖片分辨率過大

核心解決辦法:圖片窖式,我們只加載適合的潮售、需要的尺寸H睢!利用BitmapFactory.Options可完成這一項(xiàng)任務(wù)酥诽。

注意:我們要處理的分辨率的問題鞍泉,而不是圖片本身大小的問題,一個100*100的10m的圖片和一張2000*2000的2m的圖片肮帐,對我們來說咖驮,2m的那張對我們來說反而是大圖片,我們針對的是分辨率

通過BitmapFactory.Options通過指定的采樣率來縮小圖片的分辨率,把縮小到合適分辨率的圖片的放到ImageView上面來顯示托修,大大降低了內(nèi)存壓力忘巧,有效避免OOM,至于縮小的怎樣的分辨率才算合適,谷歌有為我們提供了一段代碼诀黍,就可以得出這個合適的度袋坑!這段代碼后面會貼出仗处。

inSimpleSize的比例計(jì)算

計(jì)算采樣率眯勾,主要是通過 BitmaoFactory.Options 的inSimpleSize參數(shù)進(jìn)行。
這里我們以120*800的分辨率的圖片舉例子
當(dāng)inSimpleSize為1時婆誓,圖片的分辨率就是原來的分辨率吃环,也就是1200*800
當(dāng)inSimpleSize為2時,表示圖片的寬和高都是為原來的1/2洋幻,所整張圖變成了原來的1/4
當(dāng)inSimpleSize位4時郁轻,表示圖片的寬和高都是為原來的1/4,所以整張圖也就變成原來的1/16
依次類推

inSimpleSize數(shù)值的說明

  • inSimpleSize的值必須是整數(shù)
  • inSimpleSize的值不能是負(fù)數(shù)文留,負(fù)數(shù)無效
  • inSimpleSize的值谷歌建議是2的整數(shù)倍好唯,當(dāng)然你可以寫個3,但是最好不要這么干

inSimpleSize的數(shù)值怎么確定

這里我們以為400*400圖片為例子
比如我們ImageView的大小位100*100燥翅,那么我們的骑篙,那么這時我們寫一個 inSimpleSize 為2的值,那么久剛好變成原圖的四分之一森书,那么很好靶端,剛剛好,那么如果ImageView的大小是320*120之類的呢凛膏?問題就來了杨名,怎么去的一個合適的值呢,還有就是猖毫,一個頁面有多個ImageView台谍,難道我們?yōu)槊恳粋€ImageView都去挨個計(jì)算取樣值嗎?明顯不可能吁断。

inSimpleSize怎么用俺萌铩?

谷歌為我們提供了一個規(guī)則胯府,很好用介衔,看代碼之前,我們還是文字說一下吧骂因,主要邏輯如下炎咖,分三步走:

  • (1) 將 BitmapFactory的 inJustDecodeBounds 參數(shù)設(shè)置為true,當(dāng)設(shè)置為true,代表此時不真正加載圖片乘盼,而是將圖片的原始寬和高數(shù)值讀取出來
  • (2) 利用options取出原始圖片的寬高和請求的寬高進(jìn)行比較升熊,計(jì)算出一個合適的inSimpleSize的值
  • (3) 將 BitmapFactory的 inJustDecodeBounds 參數(shù)設(shè)置為false,真正開始加載圖片(這時候加載就是經(jīng)過計(jì)算后的分辨率)

** 谷歌提供的方法:**


import java.io.FileDescriptor;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

public class ImageResizer {
    private static final String TAG = "ImageResizer";

    public ImageResizer() {
    }


    // 從資源加載 
    public Bitmap decodeSampledBitmapFromResource(Resources res,int resId, int reqWidth, int reqHeight) {
        // 設(shè)置inJustDecodeBounds = true ,表示先不加載圖片
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // 調(diào)用方法計(jì)算合適的 inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // inJustDecodeBounds 置為 false 真正開始加載圖片
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    public Bitmap decodeSampledBitmapFromFileDescriptor(FileDescriptor fd, int reqWidth, int reqHeight) {
        // 設(shè)置inJustDecodeBounds = true ,表示先不加載圖片
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fd, null, options);

        // 調(diào)用方法計(jì)算合適的 inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // inJustDecodeBounds 置為 false 真正開始加載圖片
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFileDescriptor(fd, null, options);
    }

    // 計(jì)算 BitmapFactpry 的 inSimpleSize的值的方法 
    public int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        if (reqWidth == 0 || reqHeight == 0) {
            return 1;
        }

        // 獲取圖片原生的寬和高
        final int height = options.outHeight;
        final int width = options.outWidth;
        Log.d(TAG, "origin, w= " + width + " h=" + height);
        int inSampleSize = 1;

    // 如果原生的寬高大于請求的寬高,那么將原生的寬和高都置為原來的一半 
        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

        // 主要計(jì)算邏輯 
            // Calculate the largest inSampleSize value that is a power of 2 and
            // keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        Log.d(TAG, "sampleSize:" + inSampleSize);
        return inSampleSize;
    }
}

來一個調(diào)用的代碼示例:

mIvPic.setImageBitmap(new ImageResizer().decodeSampledBitmapFromResource(getResources(),R.mipmap.test_pic,300,200));

當(dāng)前模擬器為32M運(yùn)行內(nèi)存的

注意看下面控制臺的打印信息
加載一張寬高為 5120*3200的圖片绸栅,依然沒問題级野,sampleSize為16
16*16=256,代表現(xiàn)在加載的這樣圖是原圖的256分之1.
差別好大

10-23 08:34:13.884 13265-13265/oomtest.amqr.com.oomandbitmap D/ImageResizer: origin, w= 5120 h=3200
10-23 08:34:13.884 13265-13265/oomtest.amqr.com.oomandbitmap D/ImageResizer: sampleSize:16

高效加載圖片不報(bào)OOM就先說到這里啦粹胯,下一篇再說圖片的二級緩存蓖柔,也叫圖片的存取機(jī)制
二級,即為內(nèi)存緩存风纠,本地緩存况鸣,網(wǎng)絡(luò),竹观,三者一起構(gòu)成了圖片的存取機(jī)制镐捧。
內(nèi)存緩存拿不到就去本地拿。本地拿不到就去網(wǎng)絡(luò)拿臭增。當(dāng)我們第一次獲取A圖片懂酱,肯定是是從網(wǎng)絡(luò)獲取的,網(wǎng)絡(luò)獲取后誊抛,圖片A就存儲到本地緩存列牺,就這還會緩存到內(nèi)存緩存。

緩存主要利用的一個機(jī)制是Lru芍锚,(Least Recently Used)最近最少使用的昔园。
而Lru和只要是利用兩個類,LruCache 和 DiskLruCache并炮。

LruCache主要針對的是 內(nèi)存緩存 (緩存)
DiskLruCache 主要針對的是 存儲緩存 (本地)

第二篇鏈接
安卓OOM和Bitmap圖片二級緩存機(jī)制(二)

本篇完默刚。


本篇相關(guān)參考:
Android Out Of Memory(OOM) 的詳細(xì)研究

Android應(yīng)用中OOM問題剖析和解決方案

Android開發(fā)藝術(shù)探索

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市逃魄,隨后出現(xiàn)的幾起案子荤西,更是在濱河造成了極大的恐慌,老刑警劉巖伍俘,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邪锌,死亡現(xiàn)場離奇詭異,居然都是意外死亡癌瘾,警方通過查閱死者的電腦和手機(jī)觅丰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妨退,“玉大人妇萄,你說我怎么就攤上這事蜕企。” “怎么了冠句?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵轻掩,是天一觀的道長。 經(jīng)常有香客問我懦底,道長唇牧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任聚唐,我火速辦了婚禮丐重,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拱层。我一直安慰自己弥臼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布根灯。 她就那樣靜靜地躺著,像睡著了一般掺栅。 火紅的嫁衣襯著肌膚如雪烙肺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天氧卧,我揣著相機(jī)與錄音桃笙,去河邊找鬼。 笑死沙绝,一個胖子當(dāng)著我的面吹牛搏明,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闪檬,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼星著,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了粗悯?” 一聲冷哼從身側(cè)響起虚循,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎样傍,沒想到半個月后横缔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衫哥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年茎刚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撤逢。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡膛锭,死狀恐怖捌斧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情泉沾,我是刑警寧澤捞蚂,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站跷究,受9級特大地震影響姓迅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俊马,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一丁存、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柴我,春花似錦解寝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至界睁,卻和暖如春觉增,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背翻斟。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工逾礁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人访惜。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓嘹履,卻偏偏與公主長得像,于是被迫代替她去往敵國和親债热。 傳聞我的和親對象是個殘疾皇子砾嫉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

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