android 內(nèi)存泄漏(如何防止內(nèi)存泄漏)

由于項(xiàng)目中大量出現(xiàn)內(nèi)存泄漏導(dǎo)致內(nèi)存使用量增多而不能立馬釋放,不得不研究內(nèi)存泄漏,接下來我們切入主題。
以下都是本人收集和總結(jié)的內(nèi)容:

1. 什么是內(nèi)存泄漏

一般情況下內(nèi)存泄漏是由忘記釋放分配的內(nèi)存導(dǎo)致的傅蹂,而邏輯上的內(nèi)存泄漏則是由于忘記在對象不再被使用的時(shí)候釋放對其的引用導(dǎo)致的。如果一個對象仍然存在強(qiáng)引用算凿,垃圾回收器就無法對其進(jìn)行垃圾回收份蝴。

2. android中的存儲泄漏

在安卓平臺髓棋,泄漏 Context 對象問題尤其嚴(yán)重佛玄。這是因?yàn)橄?Activity 這樣的 Context 對象會引用大量很占用內(nèi)存的對象,例如 View 層級缓醋,以及其他的資源署鸡。如果 Context 對象發(fā)生了內(nèi)存泄漏案糙,那它引用的所有對象都被泄漏了。安卓設(shè)備大多內(nèi)存有限靴庆,如果發(fā)生了大量這樣的內(nèi)存泄漏时捌,那內(nèi)存將很快耗盡。
如果一個對象的合理生命周期沒有清晰的定義炉抒,那判斷邏輯上的內(nèi)存泄漏將是一個見仁見智的問題奢讨。幸運(yùn)的是,activity 有清晰的生命周期定義焰薄,使得我們可以很明確地判斷 activity 對象是否被內(nèi)存泄漏拿诸。onDestroy() 函數(shù)將在 activity 被銷毀時(shí)調(diào)用,無論是程序員主動銷毀 activity塞茅,還是系統(tǒng)為了回收內(nèi)存而將其銷毀亩码。如果 onDestroy 執(zhí)行完畢之后,activity 對象仍被 heap root 強(qiáng)引用野瘦,那垃圾回收器就無法將其回收描沟。所以我們可以把生命周期結(jié)束之后仍被引用的 activity 定義為被泄漏的 activity。
Activity 是非常重量級的對象缅刽,所以我們應(yīng)該極力避免妨礙系統(tǒng)對其進(jìn)行回收啊掏。然而有多種方式會讓我們無意間就泄露了 activity 對象。我們把可能導(dǎo)致 activity 泄漏的情況分為兩類衰猛,一類是使用了進(jìn)程全局(process-global)的靜態(tài)變量,無論 APP 處于什么狀態(tài)刹孔,都會一直存在啡省,它們持有了對 activity 的強(qiáng)引用進(jìn)而導(dǎo)致內(nèi)存泄漏娜睛,另一類是生命周期長于 activity 的線程,它們忘記釋放對 activity 的強(qiáng)引用進(jìn)而導(dǎo)致內(nèi)存泄漏卦睹。

3. 常見導(dǎo)致App內(nèi)存泄漏的情況

3.1 靜態(tài) Activity

泄漏 activity 最簡單的方法就是在 activity 類中定義一個 static 變量畦戒,并且將其指向一個運(yùn)行中的 activity 實(shí)例。如果在 activity 的生命周期結(jié)束之前结序,沒有清除這個引用障斋,那它就會泄漏了。這是因?yàn)?activity(例如 MainActivity) 的類對象是靜態(tài)的徐鹤,一旦加載垃环,就會在 APP 運(yùn)行時(shí)一直常駐內(nèi)存,因此如果類對象不卸載返敬,其靜態(tài)成員就不會被垃圾回收遂庄。

public class MainActivity extends AppCompatActivity {

private static MainActivity activity;

@Override
protected void onCreate(Bundle savedInstanceState) {
  View saButton = findViewById(R.id.sa_button);
  saButton.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
      setStaticActivity();
      nextActivity();
    }
  });
}


void setStaticActivity() {
  activity = this;
}
  
  void nextActivity() {
        Intent intent = new Intent(this, DestinationActivity.class);
        startActivity(intent);
        SystemClock.sleep(600);
        finish();
    }
}

3.2 靜態(tài) View

另一種類似的情況是對經(jīng)常啟動的 activity 實(shí)現(xiàn)一個單例模式,讓其常駐內(nèi)存可以使它能夠快速恢復(fù)狀態(tài)劲赠。然而涛目,就像前文所述,不遵循系統(tǒng)定義的 activity 生命周期是非常危險(xiǎn)的凛澎,也是沒必要的霹肝,所以我們應(yīng)該極力避免。
但是如果我們有一個創(chuàng)建起來非常耗時(shí)的 View塑煎,在同一個 activity 不同的生命周期中都保持不變呢阿迈?所以讓我們?yōu)樗鼘?shí)現(xiàn)一個單例模式。現(xiàn)在一旦 activity 被銷毀,內(nèi)存就會泄漏轧叽!因?yàn)橐坏?view 被加入到界面中苗沧,它就會持有 context 的強(qiáng)引用,也就是我們的 activity炭晒。由于我們通過一個靜態(tài)成員引用了這個 view待逞,所以我們也就引用了 activity,因此 activity 就發(fā)生了泄漏网严。所以一定不要把加載的 view 賦值給靜態(tài)變量识樱,如果你真的需要,那一定要確保在 activity 銷毀之前將其從 view 層級中移除震束。

public class MainActivity extends AppCompatActivity {
 private static View view;
@Override
protected void onCreate(Bundle savedInstanceState) {
  View svButton = findViewById(R.id.sv_button);
  svButton.setOnClickListener(new View.OnClickListener() {
    @Override 
    public void onClick(View v) {
      setStaticView();
      nextActivity();
    }
  });
}

void setStaticView() {
  view = findViewById(R.id.sv_button);
}


}

3.3 內(nèi)部類

現(xiàn)在讓我們在 activity 內(nèi)部定義一個類怜庸,也就是內(nèi)部類。這樣做的原因有很多垢村,比如增加封裝性和可讀性割疾。如果我們創(chuàng)建了一個內(nèi)部類的對象,并且通過靜態(tài)變量持有了 activity 的引用嘉栓,那也會發(fā)生 activity 泄漏宏榕。

public class MainActivity extends AppCompatActivity {
  private static Object inner;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    
     View icButton = findViewById(R.id.ic_button);
     icButton.setOnClickListener(new View.OnClickListener() {
      @Override 
      public void onClick(View v) {
          createInnerClass();
          nextActivity();
      }});
    }

    
  void createInnerClass() {
      class InnerClass {
      }
      inner = new InnerClass();
  }
}

3.4 Handlers

同樣的拓诸,定義一個匿名的 Runnable 對象并將其提交到 Handler 上也可能導(dǎo)致 activity 泄漏。Runnable 對象間接地引用了定義它的 activity 對象麻昼,而它會被提交到 Handler 的 MessageQueue 中奠支,如果它在 activity 銷毀時(shí)還沒有被處理,那就會導(dǎo)致 activity 泄漏了抚芦。

public class MainActivity extends AppCompatActivity {
  private static Object inner;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    
      View hButton = findViewById(R.id.h_button);
      hButton.setOnClickListener(new View.OnClickListener() {
      @Override 
      public void onClick(View v) {
          createHandler();
          nextActivity();
      }
  });
 }

   void createHandler() {
    new Handler() {
        @Override public void handleMessage(Message message) {
            super.handleMessage(message);
        }
    }.postDelayed(new Runnable() {
        @Override public void run() {
            while(true);
        }
    }, Long.MAX_VALUE >> 1);
} 

3.5 Threads

同樣的倍谜,使用 Thread 和 TimerTask 也可能導(dǎo)致 activity 泄漏。

public class MainActivity extends AppCompatActivity {
  private static Object inner;
  @Override
  protected void onCreate(Bundle savedInstanceState) {

      View tButton = findViewById(R.id.t_button);
      tButton.setOnClickListener(new View.OnClickListener() {
      @Override 
      public void onClick(View v) {
          spawnThread();
          nextActivity();
      }
    });
 }
 void spawnThread() {
     new Thread() {
         @Override public void run() {
             while(true);
         }
     }.start();
 }  
}


3.6 Timer Tasks

只要它們是通過匿名類創(chuàng)建的叉抡,盡管它們在單獨(dú)的線程被執(zhí)行尔崔,它們也會持有對 activity 的強(qiáng)引用,進(jìn)而導(dǎo)致內(nèi)存泄漏卜壕。

public class MainActivity extends AppCompatActivity {
  private static Object inner;
  @Override
  protected void onCreate(Bundle savedInstanceState) {

      View tButton = findViewById(R.id.t_button);
      tButton.setOnClickListener(new View.OnClickListener() {
      @Override 
      public void onClick(View v) {
          scheduleTimer();
          nextActivity();
      }
    });
 }

void scheduleTimer() {
    new Timer().schedule(new TimerTask() {
        @Override
        public void run() {
            while(true);
        }
    }, Long.MAX_VALUE >> 1);
  }
   
}

3.7 Sensor Manager

系統(tǒng)服務(wù)可以通過 context.getSystemService 獲取您旁,它們負(fù)責(zé)執(zhí)行某些后臺任務(wù),或者為硬件訪問提供接口轴捎。如果 context 對象想要在服務(wù)內(nèi)部的事件發(fā)生時(shí)被通知鹤盒,那就需要把自己注冊到服務(wù)的監(jiān)聽器中。然而侦副,這會讓服務(wù)持有 activity 的引用侦锯,如果程序員忘記在 activity 銷毀時(shí)取消注冊,那就會導(dǎo)致 activity 泄漏了秦驯。

public class MainActivity extends AppCompatActivity {
  private static Object inner;
  @Override
  protected void onCreate(Bundle savedInstanceState) {

      View tButton = findViewById(R.id.t_button);
      tButton.setOnClickListener(new View.OnClickListener() {
      @Override 
      public void onClick(View v) {
          registerListener() ;
          nextActivity();
      }
    });
 }

  void registerListener() {
         SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
         Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
         sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
    } 
}

總結(jié):在編寫代碼時(shí)要注意釋放不該有的內(nèi)存尺碰,最壞的情況下,你的 APP 可能會由于大量的內(nèi)存泄漏而內(nèi)存耗盡译隘,進(jìn)而閃退亲桥,但它并不總是這樣。相反固耘,內(nèi)存泄漏會消耗大量的內(nèi)存题篷,但卻不至于內(nèi)存耗盡,這時(shí)厅目,APP 會由于內(nèi)存不夠分配而頻繁進(jìn)行垃圾回收番枚。垃圾回收是非常耗時(shí)的操作,會導(dǎo)致嚴(yán)重的卡頓损敷。在 activity 內(nèi)部創(chuàng)建對象時(shí)葫笼,一定要格外小心,并且要經(jīng)常測試是否存在內(nèi)存泄漏拗馒。

4. 使用as工具檢測內(nèi)存泄漏

在我們的日常追求構(gòu)建更好的應(yīng)用程序時(shí)路星,我們作為開發(fā)者需要考慮多方面的因素,其中之一是要確保我們的應(yīng)用程序不會崩潰瘟忱。崩潰的一個常見原因是內(nèi)存泄漏奥额。這方面的問題可以以各種形式表現(xiàn)出來苫幢。在大多數(shù)情況下访诱,我們看到內(nèi)存使用率穩(wěn)步上升垫挨,直到應(yīng)用程序不能分配更多的資源和必然崩潰。在Java中這往往導(dǎo)致一個OutOfMemoryException異常被拋出触菜。在某些的情況下九榔,泄漏的類甚至可以堅(jiān)持足夠長的時(shí)間來接收注冊的回調(diào),導(dǎo)致一些非常奇怪的錯誤涡相,并往往拋出了臭名昭著的IllegalStateException異常哲泊。
所以接下來用as工具檢測一些常見的內(nèi)存泄露:

4.1 系統(tǒng)服務(wù)注冊

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
}

我們讓了Android 的LocationManager通知我們位置更新。所有我們需要設(shè)置這是系統(tǒng)服務(wù)本身和一個回調(diào)來接收更新催蝗。在這里切威,我們實(shí)現(xiàn)了服務(wù)本身位置的接口,這意味著LocationManager將開始使用”牛現(xiàn)在先朦,如果該裝置被旋轉(zhuǎn),新的活動將被創(chuàng)建取代已經(jīng)注冊為位置更新舊的犬缨。由于系統(tǒng)服務(wù)肯定比其他生命周期長喳魏,使它不可能垃圾收集回收仍依賴于特定活動的資源,從而導(dǎo)致內(nèi)存泄漏怀薛。然后該裝置的反復(fù)旋轉(zhuǎn)將引起非可回收活動填滿存儲器刺彩,最終導(dǎo)致一個OutOfMemoryException異常。但為了解決內(nèi)存泄漏枝恋,我們首先必須要能夠找到它创倔。
接下來用android studio 的內(nèi)存監(jiān)控,實(shí)時(shí)監(jiān)控內(nèi)存使用與分配焚碌,從使用內(nèi)存異常中找到內(nèi)存溢出的問題:

而Android監(jiān)視器Android Studio中2.1.png

任何資源配置的交互將在這里體現(xiàn)出來畦攘,使之可以進(jìn)行跟蹤應(yīng)用程序的資源使用情況。接下來我們對上面的案例進(jìn)行分析呐能,首先開啟我們的應(yīng)用程序念搬,然后旋轉(zhuǎn)設(shè)備后,馬上執(zhí)行Dump Java Heap 摆出,就回生成一份 hprof 文件朗徊。

這么復(fù)雜的內(nèi)存堆棧。淡定偎漫,我們首先找到自己剛剛執(zhí)行的類爷恳,然后點(diǎn)擊查看Analyzer Tasks,可以看到出來一個界面把Detect Leaked Activities(檢查泄露內(nèi)存)勾選上象踊,接下來對Analysis Results里面的數(shù)據(jù)進(jìn)行分析

分析內(nèi)存結(jié)構(gòu).png

我們選中內(nèi)存泄漏的activity温亲,查看Reference Tree棚壁,可以清楚的看到一個服務(wù)的回調(diào),就是之前地位系統(tǒng)服務(wù)的回調(diào)接口栈虚。知道了內(nèi)存泄漏的地方袖外,我們就可以把他解決掉

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

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

再進(jìn)行旋轉(zhuǎn)設(shè)備就不會內(nèi)存泄漏。

4.2 內(nèi)部類

java中內(nèi)部類使用很廣泛魂务,然而有時(shí)候我們往往忽略內(nèi)部類的生命周期曼验,導(dǎo)致內(nèi)存泄漏。接下來我們分析常見的Andr??oid activity:


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);
        }
    }
}

以上這種情況非多粘姜。問題來了鬓照,AsyncActivity中創(chuàng)建了一個匿名內(nèi)部類BackgroundTask,同時(shí)開啟一個線程正在執(zhí)行任務(wù)并且持有內(nèi)存資源孤紧,如果在HTTP請求的情況下豺裆,這可能需要很長的時(shí)間,尤其在網(wǎng)速較慢的情況号显。更加容易內(nèi)存泄漏臭猜。
接下來我們進(jìn)行同樣的內(nèi)存分析:

BackgroundTask內(nèi)存分析.png

果然內(nèi)存泄漏的罪魁禍?zhǔn)资荁ackgroundTask,是不是不刺激,我們再對代碼進(jìn)行修改咙轩,執(zhí)行后再次分析获讳。

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)在,內(nèi)部類隱式引用已經(jīng)解決活喊,我們通過內(nèi)部類傳入一個控件丐膝,再進(jìn)入同樣的操作,看是否出現(xiàn)內(nèi)存泄漏

BackgroundTask構(gòu)造內(nèi)存分析.png

呵呵钾菊,有出現(xiàn)一個新的內(nèi)存泄漏帅矗,接下來我們冷靜再次分析一次,發(fā)現(xiàn)BackgroundTask中的resultTextView還有 Textview的強(qiáng)引用煞烫,那么該怎么解決這個問題了浑此,最簡單就是給resultTextView加上WeakReference,以為當(dāng)把最好一個強(qiáng)引用回收后滞详,垃圾回收器就回考慮弱引用下的回收凛俱。寫個例子大家就明白了:

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);
            }
        }
    }    
}

注意,在onPostExecute我們要檢查控件是否為空驗(yàn)證料饥,以防報(bào)空蒲犬。
在運(yùn)行分析任務(wù)activity就不再被泄漏!

4.3 匿名類

說白了就是匿名內(nèi)部類岸啡,我們接下來對最近很火的Retrofit的網(wǎng)絡(luò)調(diào)用進(jìn)行分析原叮,不廢話,直接搞:

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.
                    }
                });
    }
}

其實(shí)和內(nèi)部類分析的結(jié)果很相似,注意的是該activity的內(nèi)存一直會在網(wǎng)絡(luò)請求完畢才消失奋隶。(以后寫代碼一點(diǎn)要注意這一點(diǎn))


Retrofit網(wǎng)絡(luò)調(diào)用.png

處理結(jié)果和內(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.
        }
    }

總結(jié):
我們要學(xué)會使用工具來對自己的代碼負(fù)責(zé),對app的性能進(jìn)行提升唯欣。一些常見的問題和處理方式已經(jīng)在上面的例子中說明嘹吨,謝謝你能讀這篇博客,說明你是一個很有責(zé)任心的程序員黍聂。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末躺苦,一起剝皮案震驚了整個濱河市身腻,隨后出現(xiàn)的幾起案子产还,更是在濱河造成了極大的恐慌,老刑警劉巖嘀趟,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脐区,死亡現(xiàn)場離奇詭異,居然都是意外死亡她按,警方通過查閱死者的電腦和手機(jī)牛隅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酌泰,“玉大人媒佣,你說我怎么就攤上這事×晟玻” “怎么了默伍?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衰琐。 經(jīng)常有香客問我也糊,道長,這世上最難降的妖魔是什么羡宙? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任狸剃,我火速辦了婚禮,結(jié)果婚禮上狗热,老公的妹妹穿的比我還像新娘钞馁。我一直安慰自己,他們只是感情好匿刮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布僧凰。 她就那樣靜靜地躺著,像睡著了一般僻焚。 火紅的嫁衣襯著肌膚如雪允悦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音隙弛,去河邊找鬼架馋。 笑死,一個胖子當(dāng)著我的面吹牛全闷,可吹牛的內(nèi)容都是我干的叉寂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼总珠,長吁一口氣:“原來是場噩夢啊……” “哼屏鳍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起局服,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤钓瞭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后淫奔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體山涡,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年唆迁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸭丛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡唐责,死狀恐怖鳞溉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鼠哥,我是刑警寧澤熟菲,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站肴盏,受9級特大地震影響科盛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜菜皂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一贞绵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恍飘,春花似錦榨崩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至乳怎,卻和暖如春彩郊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工秫逝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恕出,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓违帆,卻偏偏與公主長得像浙巫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刷后,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

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

  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題的畴。內(nèi)存泄漏...
    _痞子閱讀 1,625評論 0 8
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。內(nèi)存泄漏...
    apkcore閱讀 1,217評論 2 7
  • 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題尝胆。內(nèi)存泄漏大家都不陌生了丧裁,簡單粗俗的講,...
    DreamFish閱讀 790評論 0 5
  • 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題班巩。內(nèi)存泄漏大家都不陌生了渣慕,簡單粗俗的講,...
    宇宙只有巴掌大閱讀 2,360評論 0 12
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,519評論 25 707