一篇技術(shù)好文之Android性能優(yōu)化內(nèi)存泄漏無(wú)處可藏(圖文)

默認(rèn)標(biāo)題_官方公眾號(hào)首圖_2018.04.29 (1).png

每次來(lái)公司面試的人芒篷,一般都會(huì)問(wèn)最基本的兩個(gè)問(wèn)題私植,一個(gè)是自定義View的繪制流程及事件分發(fā),第二個(gè)就是性能優(yōu)化內(nèi)存泄漏如何處理沸手?第一個(gè)問(wèn)題基本上都能說(shuō)個(gè)大概,第二個(gè)問(wèn)題其實(shí)很多工作好幾年的都不一定能回答的比較讓人滿意注簿。這里整理下基本的內(nèi)存泄漏及解決辦法契吉。使用的是LeakCannary來(lái)進(jìn)行檢測(cè)。

你能從本文了解到如下知識(shí):1. 什么是內(nèi)存泄漏 2. 內(nèi)存泄漏的分類及影響 3.常見(jiàn)的內(nèi)存泄漏及解決辦法 4.文章總結(jié)

[toc]

什么是內(nèi)存泄漏诡渴?

內(nèi)存泄漏也稱作"存儲(chǔ)滲漏"捐晶,用動(dòng)態(tài)存儲(chǔ)分配函數(shù)動(dòng)態(tài)開(kāi)辟的空間,在使用完畢后未釋放妄辩,結(jié)果導(dǎo)致一直占據(jù)該內(nèi)存單元惑灵。直到程序結(jié)束。(其實(shí)說(shuō)白了就是該內(nèi)存空間使用完畢之后未回收)即所謂內(nèi)存泄漏眼耀。再形象點(diǎn)比喻就像家里的水龍頭沒(méi)有擰緊英支,漏水了。

內(nèi)存泄漏的分類及影響哮伟?

分類:常發(fā)性內(nèi)存泄漏干花,偶發(fā)性內(nèi)存泄漏妄帘,一次性內(nèi)存泄漏,隱式內(nèi)存泄漏池凄。
危害:內(nèi)存泄漏造成的影響其實(shí)是內(nèi)存泄漏的堆積弧轧,這將會(huì)消耗系統(tǒng)所有的內(nèi)存薇组。所以一個(gè)內(nèi)存泄漏危害并不大漾橙,因?yàn)椴粫?huì)堆積稚配,而隱式內(nèi)存泄漏危害性則非常大,因?yàn)檩^之于常發(fā)性和偶發(fā)性內(nèi)存泄漏它更難被檢測(cè)到柏副。

常見(jiàn)的內(nèi)存泄漏及解決辦法:

1. 單例造成的內(nèi)存泄漏:

第一種情況:

public class LoginActivity extends Activity {
    public static LoginActivity instance;
     @Override
    protected void onCreate(Bundle savedInstanceState) {
        ……
        instance = this;
    }
}

在其他地方引用LoginActivity.instance會(huì)造成檢測(cè)如下的:

image

這種情況我們可以通過(guò)使用弱引用的方法來(lái)優(yōu)化,修改如下:

public class LoginActivity extends Activity {
    public static WeakReference<LoginActivity> instance;
     @Override
    protected void onCreate(Bundle savedInstanceState) {
        ……
        instance = new WeakReference<LoginActivity>(this);
    }
}

單例造成的內(nèi)存泄漏第二種情況(在網(wǎng)上找到的實(shí)例及圖片):

public class AppManager {
    private static AppManager instance;
    private Context context;
    private AppManager(Context context) {
        this.context = context;
    }
    public static AppManager getInstance(Context context) {
        if (instance == null) {
            instance = new AppManager(context);
        }
    return instance;
}

檢測(cè)結(jié)果如下:


image

解決辦法蚣录,使用Application的context替代Activity的context,修改后的diam如下:

public class LoginManager {
  private static LoginManager mInstance;
  private Context mContext;
  private LoginManager(Context context) {
    this.mContext = context.getApplicationContext();
  }
  public static LoginManager getInstance(Context context) {
    if (mInstance == null) {
      synchronized (LoginManager.class) {
        if (mInstance == null) {
          mInstance = new LoginManager(context);
        }
      }
    }
    return mInstance;
  }
  public void dealData() {
  }
}

2. 接口實(shí)現(xiàn)引用造成的內(nèi)存泄漏割择。

不知道這樣實(shí)現(xiàn)代碼的多不多?

public class MyApplication extends LitePalApplication{
    ……
     UnReadMsgListener unReadMsgListener;
     public void setUnReadMsgListener(UnReadMsgListener unReadMsgListener){
          this.unReadMsgListener = unReadMsgListener;//在其他頁(yè)面進(jìn)行接口實(shí)現(xiàn)
     } 
     ……
}

造成的內(nèi)存泄漏分析圖如下:

image

原因分析:在其他頁(yè)面進(jìn)行setUnReadMsgListener操作萎河,MyApplication將明顯持有對(duì)此接口的引用荔泳,此接口被Activity實(shí)現(xiàn),所以MyApplication一直持有Activity的引用虐杯。
在盡量不修改原代碼的情況下玛歌,解決辦法如下:

UnReadMsgListener unReadMsgListener;
    WeakReference<UnReadMsgListener> mListenerWeakReference;
    public void setUnReadMsgListener(UnReadMsgListener unReadMsgListener){
        mListenerWeakReference = new WeakReference<UnReadMsgListener>(unReadMsgListener);
        this.unReadMsgListener = mListenerWeakReference.get();
    }

3. 使用ViewVideo造成的內(nèi)存泄漏(MediaPlayer.mSubtitleController):

有時(shí)候?yàn)榱丝焖匍_(kāi)發(fā),經(jīng)常會(huì)在xml中使用VideoView去快速集成播放一個(gè)視頻擎椰,這樣做就會(huì)內(nèi)存泄漏支子。檢測(cè)結(jié)果如下:

image

從LeakCanary分析結(jié)果得出,是由于VideoView持有對(duì)Activity的Context的引用造成的达舒。因?yàn)槲覀儗ideoView寫(xiě)在XMl中值朋,所以默認(rèn)是應(yīng)用當(dāng)前頁(yè)面的Context的。

解決辦法:
第一種:將VideoView在代碼中實(shí)現(xiàn):

VideoView mVideoView = new VideoView(MyApplication.getContext());
//添加到父容器
……

第二種:重寫(xiě)當(dāng)前Activity頁(yè)面的attachBaseContext方法:

  @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(new ContextWrapper(newBase)
        {
            @Override
            public Object getSystemService(String name)
            {
                if (Context.AUDIO_SERVICE.equals(name))
                    return getApplicationContext().getSystemService(name);
                return super.getSystemService(name);
            }
        });
    }

4. MediaPlayer源碼存在的內(nèi)存泄漏問(wèn)題:

這個(gè)問(wèn)題是緊接上一個(gè)內(nèi)存泄漏巩搏,上面的處理方式基本能解決VideoView給我們帶來(lái)的內(nèi)存泄漏問(wèn)題昨登。這里我們來(lái)深入了解下為什么使用VideoView會(huì)造成內(nèi)存泄漏」岬祝看MediaPlayer的源碼我們可以得知:在系統(tǒng)的MediaPlayer的release過(guò)程中就mSubtitleController 資源未做處理丰辣,幸運(yùn)的是在reset中進(jìn)行此資源的處理,所以我們?cè)谑褂肕eidPlayer播放視頻后進(jìn)行資源釋放時(shí)再release時(shí)進(jìn)行下MediaPlayer的reset操作禽捆。下面我們看下MediaPlayer的源碼:

    //MediaPlayer系統(tǒng)源碼
    ……
  public void release() {
        baseRelease();
        stayAwake(false);
        updateSurfaceScreenOn();
        mOnPreparedListener = null;
        mOnBufferingUpdateListener = null;
        mOnCompletionListener = null;
        mOnSeekCompleteListener = null;
        mOnErrorListener = null;
        mOnInfoListener = null;
        mOnVideoSizeChangedListener = null;
        mOnTimedTextListener = null;
        if (mTimeProvider != null) {
            mTimeProvider.close();
            mTimeProvider = null;
        }
        mOnSubtitleDataListener = null;
        _release();
    }
    ……
    public void reset() {
        mSelectedSubtitleTrackIndex = -1;
        synchronized(mOpenSubtitleSources) {
            for (final InputStream is: mOpenSubtitleSources) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
            mOpenSubtitleSources.clear();
        }
        if (mSubtitleController != null) {//這里有對(duì)mSubtitleController進(jìn)行處理操作
            mSubtitleController.reset();
        }
        if (mTimeProvider != null) {
            mTimeProvider.close();
            mTimeProvider = null;
        }

        stayAwake(false);
        _reset();
        // make sure none of the listeners get called anymore
        if (mEventHandler != null) {
            mEventHandler.removeCallbacksAndMessages(null);
        }

        synchronized (mIndexTrackPairs) {
            mIndexTrackPairs.clear();
            mInbandTrackIndices.clear();
        };
    }

如果上面的描述不夠詳細(xì)笙什,你可以參考stackoverflow
解決辦法上面有提到過(guò),如下:

image

沒(méi)錯(cuò)睦擂,我就是截圖過(guò)來(lái)滴得湘。

image

5. Handler使用造成的內(nèi)存泄漏(MessageQueue.mMessage)

Handler 的使用造成的內(nèi)存泄漏問(wèn)題應(yīng)該說(shuō)是最為常見(jiàn)了,我們看一下下面代碼:

 public class BaseActivity extends AppCompatActivity {
     ......
     private Handler baseHandler = new Handler();
      @Override
    protected void onResume() {
         baseHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    heartBeat();
                    if (!isPause) {
                        baseHandler.postDelayed(this, 60 * 1000);
                    }
                }
            }, 100);
    }
 }

檢測(cè)到泄漏結(jié)果如下:


image

原因分析:由于 Handler 屬于 TLS(Thread Local Storage) 變量, 生命周期和 Activity 是不一致的顿仇。因此這種實(shí)現(xiàn)方式一般很難保證跟 View 或者 Activity 的生命周期保持一致淘正,故很容易導(dǎo)致無(wú)法正確釋放摆马。

解決辦法:在 Activity 中避免使用非靜態(tài)內(nèi)部類,比如上面我們將 Handler 聲明為靜態(tài)的鸿吆,則其存活期跟 Activity 的生命周期就無(wú)關(guān)了囤采。同時(shí)通過(guò)弱引用的方式引入 Activity,避免直接將 Activity 作為 context 傳進(jìn)去惩淳,最后當(dāng)我們Activity銷毀后蕉毯,Looper線程的消息隊(duì)列中可能會(huì)存在待處理的消息,所以我們?cè)贏ctivity的OnDestroy中移除消息隊(duì)列 MessageQueue 中的消息思犁。修改后代碼如下:

public class BaseActivity extends AppCompatActivity {
     ......
      private static class MyHandler extends Handler {
    private final WeakReference<SampleActivity> mActivity;
    public MyHandler(SampleActivity activity) {
      mActivity = new WeakReference<SampleActivity>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
      SampleActivity activity = mActivity.get();
      if (activity != null) {//這里切記要判空
        // ...
      }
    }
  }
  private final MyHandler baseHandler= new MyHandler(this);
      @Override
    protected void onResume() {
         baseHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    heartBeat();
                    if (!isPause) {
                        baseHandler.postDelayed(this, 60 * 1000);
                    }
                }
            }, 100);
    }
     @Override
    protected void onDestroy() {
         if (baseHandler != null) {
            baseHandler.removeCallbacks(null);
            baseHandler = null;
        }
    }
 }

當(dāng)然這里簡(jiǎn)單說(shuō)一下軟引用和弱引用的使用:記住兩點(diǎn)即可:
第一點(diǎn):如果只是想避免OutOfMemory異常的發(fā)生代虾,則可以使用軟引用。如果對(duì)于應(yīng)用的性能更在意激蹲,想盡快回收一些占用內(nèi)存比較大的對(duì)象棉磨,則可以使用弱引用。
第二點(diǎn):可以根據(jù)對(duì)象是否經(jīng)常使用來(lái)判斷選擇軟引用還是弱引用学辱。如果該對(duì)象可能會(huì)經(jīng)常使用的乘瓤,就盡量用軟引用。如果該對(duì)象不被使用的可能性更大些策泣,就可以用弱引用衙傀。

6. 匿名內(nèi)部類造成的內(nèi)存泄漏

在異步操作過(guò)程中,我們經(jīng)常會(huì)這樣做:

public class WelcomeActivity extends Activity {
    ......
    public void sel(){
         new Thread(new Runnable() {
                @Override
                public void run() {
                    SystemClock.sleep(10000);
                    //do something ... 里面持有對(duì)當(dāng)前activity的引用
                }
            }).start();
    }
}

檢測(cè)到的內(nèi)存泄漏結(jié)果如下:


image

原因分析:在Activity結(jié)束時(shí)萨咕,若線程內(nèi)依舊還有任務(wù)未完成统抬,則會(huì)發(fā)生內(nèi)存泄漏。上面的Runnable是一個(gè)內(nèi)部類任洞,因此對(duì)當(dāng)前的Activity存在一個(gè)隱式引用(文章開(kāi)頭有提到蓄喇,威脅最大的一種引用)。

解決思路:不使用匿名內(nèi)部類交掏,通過(guò)靜態(tài)內(nèi)部類來(lái)實(shí)現(xiàn)妆偏,使用弱應(yīng)用來(lái)持有Activity的引用。

解決后的代碼:

public class WelcomeActivity extends Activity {
......
public void sel(){
new Thread(new splashhandler()).start();
}
static class splashhandler implements Runnable {
public void run() {
SystemClock.sleep(10000);
WelcomeActivity welcomeActivity = welcomeActivityWeakReference.get();
if(welcomeActivity != null) //注意判空
//do something ... 里面持有對(duì)當(dāng)前activity的引用
}
}

匿名內(nèi)部類被異步線程所持有的時(shí)候盅弛,我們一定要特別小心钱骂,如果么有進(jìn)行任何處理措施,極容易出現(xiàn)內(nèi)存泄漏的情況挪鹏。下面我們?cè)俜治鲆环N使用AsyncTask過(guò)程中造成的內(nèi)存泄漏處理情況:

public class MainActivity extends Activity {
    public void sel(){
        new AsyncTask<void, void="">() {
            @Override
            protected Void doInBackground(Void... params) {
                SystemClock.sleep(10 * 1000);
                //do something ... 里面持有對(duì)當(dāng)前activity的引用
                return null;
            }
        }.execute();
    }
}

原因分析和上面是一樣的见秽,Activity結(jié)束了,異步任務(wù)還未處理完讨盒。

解決辦法:使用軟引用解取,并在Activity的onDestroy里調(diào)用AsyncTask.cancel()方法。

public class MainActivity extends Activity {
    private WeakReference<context> weakReference;
    AsyncTask asyncTask;
    public void sel(){
        asyncTask = new AsyncTask<>() {
            @Override
            protected Void doInBackground(Void... params) {
                SystemClock.sleep(10 * 1000);
                //do something ... 里面持有對(duì)當(dāng)前activity的引用
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                MainActivity activity = (MainActivity) weakReference.get();
                if (activity != null) {
                    //...
                }
            }
        };
        asyncTask.execute();
    }
     @Override
    protected void onDestroy() {
        asyncTask.cancel();
    }
}

關(guān)于異步線程內(nèi)存泄漏的原理返顺,推薦看下這篇文章深入分析 ThreadLocal 內(nèi)存泄漏問(wèn)題

7. 集合的內(nèi)存泄露問(wèn)題

通常我們會(huì)添加一些對(duì)象的引用到集合中禀苦,當(dāng)我們不需要用到該集合對(duì)象時(shí)蔓肯,我們需要及時(shí)將該集合清空掉,如果不清空振乏,將導(dǎo)致這個(gè)集合會(huì)越來(lái)越大蔗包。如果集合是靜態(tài)的話,那情況將會(huì)更嚴(yán)重慧邮,因?yàn)槁暶鳛閟tatic的生命周期和整個(gè)app進(jìn)程的生命周期一致调限。

下面代碼

public class MyApplication extends LitePalApplication {
     private static Map<String, Activity> destoryMap = new HashMap<>();
    public void registerActivity(String activityName,Activity act) {
        if (allActivities == null) {
             destoryMap.put(activityName, activity);
        }
    }

    public void unregisterActivity(String activityName) {
        destoryMap.remove(activityName);
    }
}

檢測(cè)結(jié)果如下圖:


image

HashMap的value對(duì)應(yīng)的Activity對(duì)象未釋放,這里解決辦法我們可以使用上面多次提到過(guò)的使用弱應(yīng)用去處理HashMap的Value值误澳,當(dāng)然這是在最小修改的前提下進(jìn)行耻矮。如果需要對(duì)Activity進(jìn)行管理,這里建議不要使用HashMap忆谓,可以使用HashSet去做淘钟,同樣最好存放的是弱應(yīng)用對(duì)象,而且集合列表最好不要使用static修飾陪毡。修改后的代碼如下(使用HashMap或者HashSet存儲(chǔ)對(duì)象時(shí),最好覆蓋hashCode()和equal()方法):

public class MyApplication extends LitePalApplication {
    ……
    private Set<WeakReference<Activity>> destoryMap ;
     public void registerActivity(Activity act) {
        if (allActivities == null) {
            allActivities = new HashSet<WeakReference<Activity>>();
        }
        allActivities.add(new WeakReference<Activity>(act));
    }

    public void unregisterActivity(Activity act) {
        if (allActivities != null) {
            allActivities.remove(new WeakReference<>(act));
        }
    }
}

當(dāng)然勾扭,我們?cè)谑褂眉蠒r(shí)毡琉,應(yīng)該注意不要使用staic去修飾。其次就是使用完集合之后需要將其致空妙色。如果是如下寫(xiě)法也會(huì)出現(xiàn)內(nèi)存泄漏:

public void sel(){
    Vector vector = new Vector(10);
            for (int i = 0; i < 100; i++) {
                Object o = new Object();
                vector.add(o);
                o = null;
            }
}

我們將對(duì)象置空其集合還會(huì)持有對(duì)該對(duì)象的引用桅滋,為此我們應(yīng)該在不使用Vector的時(shí)侯將vector 置null。這種情況比較常見(jiàn)的就是我們?cè)赗ecyclerview的適配器中的運(yùn)用身辨,我們?cè)诋?dāng)前活動(dòng)頁(yè)面銷毀的時(shí)候應(yīng)該將其對(duì)應(yīng)的所有集合都清空丐谋。

8.資源對(duì)象沒(méi)關(guān)閉造成的內(nèi)存泄漏

在開(kāi)發(fā)過(guò)程中我們經(jīng)常會(huì)使用到BraodcastReceiver,ContentObserver煌珊,InputStream号俐,Cursor,Stream定庵,Bitmap等資源吏饿。切記在資源不再使用的時(shí)候?qū)⑵溽尫牛P(guān)閉掉蔬浙。大多數(shù)頻發(fā)的OOM出現(xiàn)絕大部分是因?yàn)閳D片資源未回收猪落。在圖片資源使用完后可以通過(guò)recycler方法來(lái)進(jìn)行處理:

if(!mBitmap.isRecycled){
    mBitmap.recycle();
    mBitmap = null;
}

當(dāng)然,廣播的注銷畴博,內(nèi)容觀察者的注銷笨忌,輸入輸出流的關(guān)閉,cursor的關(guān)閉這些就不一一列舉了俱病。只要在使用的時(shí)候多留意下這些都不是問(wèn)題滴官疲。

總結(jié)

對(duì)于內(nèi)存泄漏問(wèn)題袱结,記住以下幾點(diǎn):
1、對(duì)于生命周期比Activity長(zhǎng)的對(duì)象如果需要應(yīng)該使用ApplicationContext袁余,在需要使用Context參數(shù)的時(shí)候先考慮Application.Context.
2擎勘、在引用組件Activity,F(xiàn)ragment時(shí)颖榜,優(yōu)先考慮使用弱引用棚饵。
3、在使用異步操作時(shí)注意Activity銷毀時(shí)掩完,需要清空任務(wù)列表噪漾,如果有使用集合,將集合清空并置空且蓬,釋放相應(yīng)的資源欣硼。
4、內(nèi)部類持有外部類的引用盡量修改成靜態(tài)內(nèi)部類中使用弱引用持有外部類的引用恶阴。
5诈胜、 留意活動(dòng)的生命周期,在使用單例冯事,靜態(tài)對(duì)象焦匈,全局性集合的時(shí)候應(yīng)該特別注意置空。

文章中部分代碼純手打昵仅,可能有個(gè)別單詞誤差缓熟,如果有誤差,還請(qǐng)各位看官理解摔笤,如果能留言指出就十分感謝了够滑。


image

等等,最后:盜用大牛的一句話吕世,技術(shù)無(wú)罪彰触,我是aserbao,微信公眾號(hào)aserbao寞冯,微博同名渴析。隨時(shí)歡迎撩(學(xué)習(xí)交流)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吮龄,一起剝皮案震驚了整個(gè)濱河市俭茧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌漓帚,老刑警劉巖母债,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡毡们,警方通過(guò)查閱死者的電腦和手機(jī)迅皇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)衙熔,“玉大人登颓,你說(shuō)我怎么就攤上這事『炻龋” “怎么了框咙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)痢甘。 經(jīng)常有香客問(wèn)我喇嘱,道長(zhǎng),這世上最難降的妖魔是什么塞栅? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任者铜,我火速辦了婚禮,結(jié)果婚禮上放椰,老公的妹妹穿的比我還像新娘作烟。我一直安慰自己,他們只是感情好砾医,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布俗壹。 她就那樣靜靜地躺著,像睡著了一般藻烤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上头滔,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天怖亭,我揣著相機(jī)與錄音,去河邊找鬼坤检。 笑死兴猩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的早歇。 我是一名探鬼主播倾芝,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼箭跳!你這毒婦竟也來(lái)了晨另?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谱姓,失蹤者是張志新(化名)和其女友劉穎借尿,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡路翻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年狈癞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茂契。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蝶桶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掉冶,到底是詐尸還是另有隱情真竖,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布郭蕉,位于F島的核電站疼邀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏召锈。R本人自食惡果不足惜旁振,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涨岁。 院中可真熱鬧拐袜,春花似錦、人聲如沸梢薪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)秉撇。三九已至甜攀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間琐馆,已是汗流浹背规阀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘦麸,地道東北人谁撼。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像滋饲,于是被迫代替她去往敵國(guó)和親厉碟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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