Android內(nèi)存優(yōu)化——內(nèi)存泄露檢測分析方法

上一篇文章總結了一些常見的內(nèi)存泄露場景及優(yōu)化方案,這篇文章繼續(xù)總結內(nèi)存泄露的一些常用的檢測和分析方法凤薛。

Lint代碼檢查

AndroidStudio自動Lint代碼檢查工具墅拭,一些常見的代碼警告Lint工具都會給我們提示舒憾。使用也比較簡單:

Analyze —> Inspect Code 然后選擇檢查范圍:

Lint使用-1
Lint使用-2
Lint使用-3

比如如果存在非靜態(tài)內(nèi)部類的Handler,可能會導致內(nèi)存泄露唤蔗,檢查結果就會顯示在AndroidStudio的控制臺探遵。

其實,只要我們在設置里面勾選了Lint代碼檢查(AnroidStudio默認是勾選了的)妓柜,在寫代碼的時候就會自動提示可能發(fā)生內(nèi)存泄露别凤。

Lint檢查代碼內(nèi)存泄露
Lint提示內(nèi)存泄露

通常在寫Handler、靜態(tài)字段领虹、標記對象等可能存在的內(nèi)存泄露時规哪,Lint檢查工具都會有一個警告提示信息,我們可以根據(jù)Lint檢查的提示信息來避免這些有可能發(fā)生的內(nèi)存泄露努酸。

Android Monitor

在AndroidStudio中逗爹,可以通過Monitors來監(jiān)控Memory、CPU色瘩、Network勋篓、GPU等。在Monitors監(jiān)控中,我們可以獲取內(nèi)存的各種信息來分析內(nèi)存泄露救鲤。

首先運行工程后犹赖,打開控制臺的Android Monitor:

Android Monitor

在運行設備中使用app(各個頁面的跳轉,使用相應的各種功能)芍秆,就可以看到內(nèi)存使用的不斷變化:

內(nèi)存使用變化

淡藍色和淺灰色區(qū)域就是內(nèi)存分配的變化過程华坦,淺灰色表示空閑內(nèi)存寝优,淡藍色表示使用內(nèi)存捷沸。

通常,我們在打開一個新的頁面后,使用的內(nèi)存就會增加柜裸,相應的,關閉一個頁面后沥阳,系統(tǒng)執(zhí)行了GC桂敛,使用的內(nèi)存應該下降。如果我們在退出界面并執(zhí)行GC后橡淆,內(nèi)存使用并未下降明顯杂数,或者使用內(nèi)存沒有下降初始的使用大小遇八,那么有可能就發(fā)生了內(nèi)存泄露。

運行工程耍休,在設備上操作app刃永,觀察Monitor中內(nèi)存的變化,點擊 initiate GC 觸發(fā)GC羊精,然后點擊Dump Java Heap轉出堆信息斯够,稍等片刻,生成hprof文件喧锦,生成后會在Studio中自動打開读规。

hprof文件

點擊右側的Analyzer Tasks,再點擊Perform Analyzer燃少,展開下面分析結果
中的 Leaked Activities 就可以看到發(fā)生內(nèi)存泄露的Activity了束亏。


Monitor內(nèi)存泄露分析

可以根據(jù)左側的引用樹,來查找持有Activity引用的位置阵具,從而判斷出哪個地方導致了內(nèi)存泄露碍遍。

Mat

使用第三方的Mat工具來分析內(nèi)存泄露,需要在官網(wǎng)下載獨立版的Mat阳液。

將Android Monitor生成的hprof文件導出為標準的hprof文件(必須這樣導出怕敬,直接copy出來會報錯的):

導出hprof文件

使用Mat打開導出的hprof文件:

Mat打開hprof文件

點擊Histogram(直方圖),可以看到類對應的實例數(shù)量的統(tǒng)計帘皿。

直方圖

在Class Name下面輸入需要匹配的類名东跪,根據(jù)類來查看它的實例的引用,進而分析是否存在內(nèi)存泄露鹰溜。

類的實例

可以看到TestActivity和MyHandler都只有一個實例被引用虽填。

TestActivity點擊右鍵—>Merge Shortest Paths to GC Roots —>exclude all phantom/weak/soft etc.references。

Merge Shortest Paths to GC Roots 可以查看一個對象到RC Roots是否存在引用鏈相連接曹动, 在JAVA中是通過可達性(Reachability Analysis)來判斷對象是否存活斋日,這個算法的基本思想是通過一系列的稱謂"GC Roots"的對象作為起始點,從這些節(jié)點開始向下搜索仁期,搜索所走得路徑稱為引用鏈桑驱,當一個對象到GC Roots沒有任何引用鏈相連則該對象被判定為可以被回收的對象竭恬,反之不能被回收跛蛋,我們可以選擇 exclude all phantom/weak/soft etc.references(排查虛引用/弱引用/軟引用等)因為被虛引用/弱引用/軟引用的對象可以直接被GC給回收。

參考自Android 性能優(yōu)化之使用MAT分析內(nèi)存泄露問題痊硕。

TestActivity實例 RC Roots引用鏈

可以看到TestActivity實例存在GC Roots鏈赊级,TextActivity實例被mMessageQueue.mMessae.target.this$0持有,那么發(fā)生了內(nèi)存泄露岔绸,我們可以根據(jù)引用鏈來在代碼中找到內(nèi)存泄露的位置理逊。

LeakCanary

LeakCanary是square開源的檢測內(nèi)存泄露的第三方庫橡伞。它最大的有點就是開發(fā)者只需要添加簡單代碼,app在運行時如果發(fā)生了內(nèi)存泄露晋被,就會很直觀的將內(nèi)存泄露的詳細信息展示在通知欄上兑徘,這樣避免了Android Monitor或者Mat等工具的繁瑣的分析過程。

項目地址:https://github.com/square/leakcanary

在Gradle文件中添加依賴:

 dependencies {
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
 }

在入口的Application中進行初始化:

public class App extends Application {

    // 模擬內(nèi)存泄露場景
    public static ArrayList<Activity> sActivities = new ArrayList<>();

    @Override
    public void onCreate() {
        super.onCreate();
        if (LeakCanary.isInAnalyzerProcess(this)) {
            // This process is dedicated to LeakCanary for heap analysis.
            // You should not init your app in this process.
            return;
        }
        LeakCanary.install(this);
        // Normal app init code...
    }
}

在Application中新建一個靜態(tài)List羡洛,里面存儲Activity挂脑,來模擬內(nèi)存泄露案例:

public class TestActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        App.sActivities.add(this);
    }

    public void back(View view) {
        finish();
    }
}

運行app后,在控制臺可以看到LeakCanary的日志:

04-25 10:20:46.793 D/LeakCanary: In com.xiao.memoryleakexample:1.0:1.
04-25 10:20:46.793 D/LeakCanary: * com.xiao.memoryleakexample.TestActivity has leaked:
04-25 10:20:46.793 D/LeakCanary: * GC ROOT static com.xiao.memoryleakexample.app.App.sActivities
04-25 10:20:46.793 D/LeakCanary: * references java.util.ArrayList.array
04-25 10:20:46.793 D/LeakCanary: * references array java.lang.Object[].[0]
04-25 10:20:46.793 D/LeakCanary: * leaks com.xiao.memoryleakexample.TestActivity instance
04-25 10:20:46.793 D/LeakCanary: * Retaining: 88 KB.
04-25 10:20:46.793 D/LeakCanary: * Reference Key: 915bf11a-db9f-468e-8064-d6fb103710e9
04-25 10:20:46.793 D/LeakCanary: * Device: OPPO OPPO OPPO R9 Plusm A R9PlusmA
04-25 10:20:46.793 D/LeakCanary: * Android Version: 5.1.1 API: 22 LeakCanary: 1.5 00f37f5
04-25 10:20:46.793 D/LeakCanary: * Durations: watch=5049ms, gc=207ms, heap dump=979ms, analysis=122889ms
04-25 10:20:46.793 D/LeakCanary: * Details:
04-25 10:20:46.793 D/LeakCanary: * Class com.xiao.memoryleakexample.app.App
04-25 10:20:46.793 D/LeakCanary: |   static $staticOverhead = byte[24]@314667009 (0x12c17001)
04-25 10:20:46.793 D/LeakCanary: |   static sActivities = java.util.ArrayList@315492800 (0x12ce09c0)
04-25 10:20:46.793 D/LeakCanary: |   static serialVersionUID = -920324649544707127
04-25 10:20:46.793 D/LeakCanary: |   static $change = null
04-25 10:20:46.793 D/LeakCanary: * Instance of java.util.ArrayList
04-25 10:20:46.793 D/LeakCanary: |   static $staticOverhead = byte[16]@1893824473 (0x70e177d9)
04-25 10:20:46.793 D/LeakCanary: |   static MIN_CAPACITY_INCREMENT = 12
04-25 10:20:46.793 D/LeakCanary: |   static serialVersionUID = 8683452581122892189
04-25 10:20:46.793 D/LeakCanary: |   array = java.lang.Object[12]@318048768 (0x12f50a00)
04-25 10:20:46.793 D/LeakCanary: |   size = 1
04-25 10:20:46.793 D/LeakCanary: |   modCount = 1
04-25 10:20:46.793 D/LeakCanary: * Array of java.lang.Object[]
04-25 10:20:46.793 D/LeakCanary: |   [0] = com.xiao.memoryleakexample.TestActivity@316091520 (0x12d72c80)
04-25 10:20:46.793 D/LeakCanary: |   [1] = null
04-25 10:20:46.793 D/LeakCanary: |   [2] = null
04-25 10:20:46.793 D/LeakCanary: |   [3] = null
04-25 10:20:46.793 D/LeakCanary: |   [4] = null
04-25 10:20:46.793 D/LeakCanary: |   [5] = null
04-25 10:20:46.793 D/LeakCanary: |   [6] = null
04-25 10:20:46.793 D/LeakCanary: |   [7] = null
04-25 10:20:46.793 D/LeakCanary: |   [8] = null
04-25 10:20:46.793 D/LeakCanary: |   [9] = null
04-25 10:20:46.793 D/LeakCanary: |   [10] = null
04-25 10:20:46.793 D/LeakCanary: |   [11] = null
04-25 10:20:46.793 D/LeakCanary: * Instance of com.xiao.memoryleakexample.TestActivity
04-25 10:20:46.793 D/LeakCanary: |   static $staticOverhead = byte[16]@316125185 (0x12d7b001)
04-25 10:20:46.793 D/LeakCanary: |   static serialVersionUID = 836998863274086997
04-25 10:20:46.793 D/LeakCanary: |   static $change = null
04-25 10:20:46.793 D/LeakCanary: |   mHandler = com.xiao.memoryleakexample.TestActivity$MyHandler@318005952 (0x12f462c0)
04-25 10:20:46.793 D/LeakCanary: |   mDelegate = android.support.v7.app.AppCompatDelegateImplV14@314816320 (0x12c3b740)
04-25 10:20:46.793 D/LeakCanary: |   mEatKeyUpEvent = false
04-25 10:20:46.793 D/LeakCanary: |   mResources = null
04-25 10:20:46.793 D/LeakCanary: |   mThemeId = 2131230884
04-25 10:20:46.793 D/LeakCanary: |   mCreated = true
04-25 10:20:46.793 D/LeakCanary: |   mFragments = android.support.v4.app.FragmentController@317876896 (0x12f26aa0)
04-25 10:20:46.793 D/LeakCanary: |   mHandler = android.support.v4.app.FragmentActivity$1@318005920 (0x12f462a0)
04-25 10:20:46.793 D/LeakCanary: |   mNextCandidateRequestIndex = 0
04-25 10:20:46.793 D/LeakCanary: |   mOptionsMenuInvalidated = false
04-25 10:20:46.793 D/LeakCanary: |   mPendingFragmentActivityResults = android.support.v4.util.SparseArrayCompat@318008352 (0x12f46c20)
04-25 10:20:46.793 D/LeakCanary: |   mReallyStopped = true
04-25 10:20:46.793 D/LeakCanary: |   mRequestedPermissionsFromFragment = false
04-25 10:20:46.793 D/LeakCanary: |   mResumed = false
04-25 10:20:46.793 D/LeakCanary: |   mRetaining = false
04-25 10:20:46.793 D/LeakCanary: |   mStopped = true
04-25 10:20:46.793 D/LeakCanary: |   mStartedActivityFromFragment = false
04-25 10:20:46.793 D/LeakCanary: |   mStartedIntentSenderFromFragment = false
04-25 10:20:46.793 D/LeakCanary: |   mExtraDataMap = android.support.v4.util.SimpleArrayMap@318005888 (0x12f46280)
04-25 10:20:46.793 D/LeakCanary: |   mActionBar = null
04-25 10:20:46.793 D/LeakCanary: |   mActivityInfo = android.content.pm.ActivityInfo@318009472 (0x12f47080)
04-25 10:20:46.793 D/LeakCanary: |   mActivityTransitionState = android.app.ActivityTransitionState@317937344 (0x12f356c0)
04-25 10:20:46.793 D/LeakCanary: |   mAllLoaderManagers = android.util.ArrayMap@318081312 (0x12f58920)
04-25 10:20:46.793 D/LeakCanary: |   mApplication = com.xiao.memoryleakexample.app.App@315492832 (0x12ce09e0)
04-25 10:20:46.793 D/LeakCanary: |   mCalled = true
04-25 10:20:46.793 D/LeakCanary: |   mChangeCanvasToTranslucent = false
04-25 10:20:46.793 D/LeakCanary: |   mChangingConfigurations = false
04-25 10:20:46.793 D/LeakCanary: |   mCheckedForLoaderManager = true
04-25 10:20:46.793 D/LeakCanary: |   mComponent = android.content.ComponentName@314990768 (0x12c660b0)
04-25 10:20:46.793 D/LeakCanary: |   mConfigChangeFlags = 0
04-25 10:20:46.793 D/LeakCanary: |   mContainer = android.app.Activity$1@317876848 (0x12f26a70)
04-25 10:20:46.793 D/LeakCanary: |   mCurrentConfig = android.content.res.Configuration@317856672 (0x12f21ba0)
04-25 10:20:46.793 D/LeakCanary: |   mDecor = null
04-25 10:20:46.793 D/LeakCanary: |   mDefaultKeyMode = 0
04-25 10:20:46.793 D/LeakCanary: |   mDefaultKeySsb = null
04-25 10:20:46.793 D/LeakCanary: |   mDestroyed = true
04-25 10:20:46.793 D/LeakCanary: |   mDoReportFullyDrawn = false
04-25 10:20:46.793 D/LeakCanary: |   mEmbeddedID = null
04-25 10:20:46.793 D/LeakCanary: |   mEnableDefaultActionBarUp = false
04-25 10:20:46.793 D/LeakCanary: |   mEnterTransitionListener = android.app.SharedElementCallback$1@1893595344 (0x70ddf8d0)
04-25 10:20:46.793 D/LeakCanary: |   mExitTransitionListener = android.app.SharedElementCallback$1@1893595344 (0x70ddf8d0)
04-25 10:20:46.793 D/LeakCanary: |   mFinished = true
04-25 10:20:46.793 D/LeakCanary: |   mFragments = android.app.FragmentManagerImpl@317856448 (0x12f21ac0)
04-25 10:20:46.793 D/LeakCanary: |   mHandler = android.os.Handler@318005856 (0x12f46260)
04-25 10:20:46.793 D/LeakCanary: |   mIdent = 578025123
04-25 10:20:46.793 D/LeakCanary: |   mInstanceTracker = android.os.StrictMode$InstanceTracker@317876864 (0x12f26a80)
04-25 10:20:46.793 D/LeakCanary: |   mInstrumentation = android.app.Instrumentation@315352176 (0x12cbe470)
04-25 10:20:46.793 D/LeakCanary: |   mIntent = android.content.Intent@317362304 (0x12ea9080)
04-25 10:20:46.793 D/LeakCanary: |   mLastNonConfigurationInstances = null
04-25 10:20:46.793 D/LeakCanary: |   mLoaderManager = null
04-25 10:20:46.793 D/LeakCanary: |   mLoadersStarted = false
04-25 10:20:46.793 D/LeakCanary: |   mMainThread = android.app.ActivityThread@314856000 (0x12c45240)
04-25 10:20:46.803 D/LeakCanary: |   mManagedCursors = java.util.ArrayList@318005792 (0x12f46220)
04-25 10:20:46.803 D/LeakCanary: |   mManagedDialogs = null
04-25 10:20:46.803 D/LeakCanary: |   mMenuInflater = null
04-25 10:20:46.803 D/LeakCanary: |   mParent = null
04-25 10:20:46.803 D/LeakCanary: |   mReferrer = java.lang.String@314984512 (0x12c64840)
04-25 10:20:46.803 D/LeakCanary: |   mResultCode = 0
04-25 10:20:46.803 D/LeakCanary: |   mResultData = null
04-25 10:20:46.803 D/LeakCanary: |   mResumed = false
04-25 10:20:46.803 D/LeakCanary: |   mSearchManager = null
04-25 10:20:46.803 D/LeakCanary: |   mStartedActivity = false
04-25 10:20:46.803 D/LeakCanary: |   mStopped = true
04-25 10:20:46.803 D/LeakCanary: |   mTemporaryPause = false
04-25 10:20:46.803 D/LeakCanary: |   mTitle = java.lang.String@316164352 (0x12d84900)
04-25 10:20:46.803 D/LeakCanary: |   mTitleColor = 0
04-25 10:20:46.803 D/LeakCanary: |   mTitleReady = true
04-25 10:20:46.803 D/LeakCanary: |   mToken = android.os.BinderProxy@314983040 (0x12c64280)
04-25 10:20:46.803 D/LeakCanary: |   mTranslucentCallback = null
04-25 10:20:46.803 D/LeakCanary: |   mUiThread = java.lang.Thread@1967775656 (0x7549dfa8)
04-25 10:20:46.803 D/LeakCanary: |   mVisibleBehind = false
04-25 10:20:46.803 D/LeakCanary: |   mVisibleFromClient = true
04-25 10:20:46.803 D/LeakCanary: |   mVisibleFromServer = true
04-25 10:20:46.803 D/LeakCanary: |   mVoiceInteractor = null
04-25 10:20:46.803 D/LeakCanary: |   mWindow = com.android.internal.policy.impl.PhoneWindow@315631936 (0x12d02940)
04-25 10:20:46.803 D/LeakCanary: |   mWindowAdded = true
04-25 10:20:46.803 D/LeakCanary: |   mWindowManager = android.view.WindowManagerImpl@318006848 (0x12f46640)
04-25 10:20:46.803 D/LeakCanary: |   mInflater = com.android.internal.policy.impl.PhoneLayoutInflater@317929312 (0x12f33760)
04-25 10:20:46.803 D/LeakCanary: |   mOverrideConfiguration = null
04-25 10:20:46.803 D/LeakCanary: |   mResources = android.content.res.Resources@314591360 (0x12c04880)
04-25 10:20:46.803 D/LeakCanary: |   mTheme = android.content.res.Resources$Theme@318006400 (0x12f46480)
04-25 10:20:46.803 D/LeakCanary: |   mThemeResource = 2131230884
04-25 10:20:46.803 D/LeakCanary: |   mBase = android.app.ContextImpl@317145792 (0x12e742c0)
04-25 10:20:46.803 D/LeakCanary: * Excluded Refs:
04-25 10:20:46.803 D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mNextServedView
04-25 10:20:46.803 D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mServedView
04-25 10:20:46.803 D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mServedInputConnection
04-25 10:20:46.803 D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mCurRootView
04-25 10:20:46.803 D/LeakCanary: | Field: android.animation.LayoutTransition$1.val$parent
04-25 10:20:46.803 D/LeakCanary: | Field: android.view.textservice.SpellCheckerSession$1.this$0
04-25 10:20:46.803 D/LeakCanary: | Field: android.support.v7.internal.widget.ActivityChooserModel.mActivityChoserModelPolicy
04-25 10:20:46.803 D/LeakCanary: | Field: android.widget.ActivityChooserModel.mActivityChoserModelPolicy
04-25 10:20:46.803 D/LeakCanary: | Field: android.accounts.AccountManager$AmsTask$Response.this$1
04-25 10:20:46.803 D/LeakCanary: | Field: android.media.MediaScannerConnection.mContext
04-25 10:20:46.803 D/LeakCanary: | Field: android.os.UserManager.mContext
04-25 10:20:46.803 D/LeakCanary: | Field: android.media.AudioManager$1.this$0
04-25 10:20:46.803 D/LeakCanary: | Field: android.widget.Editor$Blink.this$0
04-25 10:20:46.803 D/LeakCanary: | Field: android.net.ConnectivityManager.sInstance
04-25 10:20:46.803 D/LeakCanary: | Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
04-25 10:20:46.803 D/LeakCanary: | Static field: android.text.TextLine.sCached
04-25 10:20:46.803 D/LeakCanary: | Thread:FinalizerWatchdogDaemon (always)
04-25 10:20:46.803 D/LeakCanary: | Thread:main (always)
04-25 10:20:46.803 D/LeakCanary: | Thread:LeakCanary-Heap-Dump (always)
04-25 10:20:46.803 D/LeakCanary: | Class:java.lang.ref.WeakReference (always)
04-25 10:20:46.803 D/LeakCanary: | Class:java.lang.ref.SoftReference (always)
04-25 10:20:46.803 D/LeakCanary: | Class:java.lang.ref.PhantomReference (always)
04-25 10:20:46.803 D/LeakCanary: | Class:java.lang.ref.Finalizer (always)
04-25 10:20:46.803 D/LeakCanary: | Class:java.lang.ref.FinalizerReference (always)

日志當中展示了詳細的內(nèi)存泄露信息欲侮。同時崭闲,在運行設備上,會以通知的形式展示內(nèi)存泄露:

LeakCanary內(nèi)存泄露通知

點擊通知欄后會展示消息的內(nèi)存泄露信息威蕉,包括泄露的具體實例刁俭、以及發(fā)生在哪個類中的具體引用位置:

LeakCanary內(nèi)存泄露詳細信息-1
LeakCanary內(nèi)存泄露詳細信息-2
最后

Lint、Android Monitor韧涨、Mat牍戚,以及LeakCanary都能讓我們在平常的開發(fā)過程中非常有效的避免內(nèi)存泄露,至于選擇哪個工具虑粥,那種方式翘魄,就看自己平常的習慣了。個人還是更喜歡使用LeakCanary舀奶,只需要簡單的集成暑竟,就可以更加快速,直觀展示內(nèi)存泄露的信息育勺。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末但荤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子涧至,更是在濱河造成了極大的恐慌腹躁,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件南蓬,死亡現(xiàn)場離奇詭異纺非,居然都是意外死亡,警方通過查閱死者的電腦和手機赘方,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門烧颖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窄陡,你說我怎么就攤上這事炕淮。” “怎么了跳夭?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵涂圆,是天一觀的道長们镜。 經(jīng)常有香客問我,道長润歉,這世上最難降的妖魔是什么模狭? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮踩衩,結果婚禮上胞皱,老公的妹妹穿的比我還像新娘。我一直安慰自己九妈,他們只是感情好反砌,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著萌朱,像睡著了一般宴树。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晶疼,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天酒贬,我揣著相機與錄音,去河邊找鬼翠霍。 笑死锭吨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的寒匙。 我是一名探鬼主播零如,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锄弱!你這毒婦竟也來了考蕾?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤会宪,失蹤者是張志新(化名)和其女友劉穎肖卧,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掸鹅,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡塞帐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了巍沙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片葵姥。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赎瞎,靈堂內(nèi)的尸體忽然破棺而出牌里,到底是詐尸還是另有隱情颊咬,我是刑警寧澤务甥,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布牡辽,位于F島的核電站,受9級特大地震影響敞临,放射性物質發(fā)生泄漏态辛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一挺尿、第九天 我趴在偏房一處隱蔽的房頂上張望奏黑。 院中可真熱鬧,春花似錦编矾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽城须。三九已至,卻和暖如春凹蜈,著一層夾襖步出監(jiān)牢的瞬間限寞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工仰坦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留履植,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓悄晃,卻偏偏與公主長得像玫霎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子妈橄,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

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