国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

一個優秀程序員不可避免的問題:內存泄漏

tanglijun / 1360人閱讀

摘要:前言內存泄漏,一個說大不大說下不小的瑕疵。所以今天咱們來聊一聊中的內存泄漏。主線程進行耗時操作,每一個開發者都明白這意味著什么所以內存泄漏足夠嚴重,其危害還是很嚴重的。

前言

內存泄漏,一個說大不大說下不小的瑕疵。作為開發者,我們都很清楚內存泄漏是我們代碼問題導致的。但是話說回來,泄漏后果會很嚴重嘛?這不好說,如果我們不泄漏Bitmap這種大內存的對象,那么修補內存泄漏就像雞肋一樣,“食之無味,棄之可惜”。 就比如說我們項目組,近2000w的DAU,只要不明顯影響用戶體驗,一切以上需求為主…

但是這作為一個996福報碼農,不能只挖坑,不填坑,畢竟技術債都是要還的。所以今天咱們來聊一聊Android中的內存泄漏。這篇文章總結翻譯了外國友人的一篇文章:原文如下

techbeacon.com/app-dev-tes…

一、理論

先上一張圖:

解釋一下這張圖,每個Android(或Java)應用程序都有一個起點(GC Root),從這個點中實例化對象、調用方法。。一些對象直接引用GC Root,另一些對象又引用了這些對象。因此,形成了引用鏈,就像上圖一樣。因此垃圾收集器從GC Root開始并遍歷直接或間接鏈接到GC Root的對象。在此過程結束時,脫離GC Root的對象/對象鏈將被回收。

接下來咱們再想另一個問題:

什么是內存泄漏?

有了上圖,理解內存泄漏的概念就很簡單,說白了就是:長生命周期對象A持有了短生命周期的對象B,那么只要A不脫離GC Root的鏈,那么B對象永遠沒有可能被回收,因此B就泄漏了。

有什么危害?

危害的話,如開篇所說。如果泄漏的內存很小,幾字節,幾kb….對于現在的機器性能,就像星爵打滅霸…“傷害”基本無視。但是如果泄漏的足夠多,普通的GC無法回收這些泄漏的內存,那么堆將持續增加,當堆足夠大的時候,就會觸發“stop-the-world” GC,直接在主線程進行耗時的GC。

主線程進行耗時操作,每一個android開發者都明白這意味著什么….

所以內存泄漏足夠嚴重,其危害還是很嚴重的。

二、實踐

對于我們日常開發來說,有比較多的場景稍不注意就會存在內存泄漏的風險。讓我們一起留意一下:

2.1、內部類Inner classes

內部類存在內存泄漏的風險,是一個老生常談的話題。說白了就是因為我們在new一個內部類時,編譯器會在編譯時讓這個內部類的實例持有外部對象。

這也就是,為啥我們的內部類可以引用到外部類變量、方法的原因。

上段代碼:

public class BadActivity extends Activity {

??? private TextView mMessageView;

??? @Override
??? protected void onCreate(Bundle savedInstanceState) {
??????? super.onCreate(savedInstanceState);
??????? setContentView(R.layout.layout_bad_activity);
??????? mMessageView = (TextView) findViewById(R.id.messageView);

??????? new LongRunningTask().execute();
??? }

??? private class LongRunningTask extends AsyncTask<Void, Void, String> {

??????? @Override
??????? protected String doInBackground(Void... params) {
??????????? return "Am finally done!";
??????? }

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

大家應該都能看出這里的問題吧。作為非靜態內部類的LongRunningTask,會持有BadActivity。并且LongRunningTask是一個長時間任務,也就是說,在這個任務沒有完成時,BadActivity是不會被回收的,因此我們的BadActivity就被泄漏了。那么怎么改呢?

解決原理

首先我不能讓LongRunningTask持有BadActivity。那么我們需要使用靜態內部類(static class)。這樣的確不會持有BadActivity,但是問題來了,我們LongRunningTask不持有BadActivity,也就意味著沒辦法引用到BadActivity中的變量,那么我們的更新UI的操作就做不了,也就是說還是要顯示的傳一個BadActivity中我們需要的變量進來…但是這樣有造成了同樣的泄漏問題。

因此,我們需要對傳入的變量使用WeakReference進行包一層。但發生GC的時候,告訴GC收集器“我”可以被回收。

上改造后的代碼:

public class GoodActivity extends Activity {

??? private AsyncTask mLongRunningTask;
??? private TextView mMessageView;

??? @Override
??? protected void onCreate(Bundle savedInstanceState) {
??????? super.onCreate(savedInstanceState);
??????? setContentView(R.layout.layout_good_activity);
??????? mMessageView = (TextView) findViewById(R.id.messageView);

??????? mLongRunningTask = new LongRunningTask(mMessageView).execute();
??? }

??? @Override
??? protected void onDestroy() {
??????? super.onDestroy();
??????? mLongRunningTask.cancel(true);
??? }

??? private static class LongRunningTask extends AsyncTask<Void, Void, String> {

??????? private final WeakReference messageViewReference;

??????? public LongRunningTask(TextView messageView) {
??????????? this.messageViewReference = new WeakReference<>(messageView);
??????? }

??????? @Override
??????? protected String doInBackground(Void... params) {
??????????? String message = null;
??????????? if (!isCancelled()) {
??????????????? message = "I am finally done!";
??????????? }
??????????? return message;
??????? }

??????? @Override
??????? protected void onPostExecute(String result) {
??????????? TextView view = messageViewReference.get();
??????????? if (view != null) {
??????????????? view.setText(result);
??????????? }
??????? }
??? }
}
2.2、匿名類 Anonymous classes

這一類和2.1很類似。本質都是持有外部對象的引用。

上一段很常見的代碼:

public class MoviesActivity extends Activity {

??? private TextView mNoOfMoviesThisWeek;

??? @Override
??? protected void onCreate(Bundle savedInstanceState) {
??????? super.onCreate(savedInstanceState);
??????? setContentView(R.layout.layout_movies_activity);
??????? mNoOfMoviesThisWeek = (TextView) findViewById(R.id.no_of_movies_text_view);

??????? MoviesRepository repository = ((MoviesApp) getApplication()).getRepository();
??????? repository.getMoviesThisWeek()
??????????????? .enqueue(new Callback>() {
???????????????????
??????????????????? @Override
??????????????????? public void onResponse(Call> call,
?????????????????????????????????????????? Response> response) {
??????????????????????? int numberOfMovies = response.body().size();
??????????????????????? mNoOfMoviesThisWeek.setText("No of movies this week: " + String.valueOf(numberOfMovies));
??????????????????? }

??????????????????? @Override
??????????????????? public void onFailure(Call> call, Throwable t) {
??????????????????????? // Oops.
??????????????????? }
??????????????? });
??? }
}
2.3、注冊Listener
SingleInstance.setMemoryLeakListener(new OnMemoryLeakListener(){
	//…..
})

這里寫了段很常見的偽碼,一個單例的對象,register了一個Listener,并且這個Listener被單例的一個成員變量引用。

OK,那么問題很明顯了。單例作為靜態變量,肯定是一直存在的。而其內部持有了Listener,而Listener作為一個匿名類,有持有了外部對象的引用。因此這條GC鏈上的所有對象都不會被釋放。

解決也很簡單,適當的時機,在單例中將Listener的引用置為null。這樣,Listener和單例之間的引用關系斷了,Listener鏈上的所有內容就可以被正常釋放掉了。也就是咱們常做的在onDestory()進行unRegisterListener的操作。

類似不注意的內容,還包括Lambda。不過有一點值得注意的,在Kotlin的Lambda中,如果我們沒有使用外部對象的變量或者方法,那么Kotlin在編譯時,這個Lambda是不會持有外部對象的引用的。也算是Kotlin的一些優化吧

2.4、Contexts

上下文的濫用,也是泄漏的大客戶。不過大家針對這類問題應該比較熟悉。

比如:長時間存活的對象,不建議持有Activity的context,而是使用ApplicationContext。如果ApplicationContext沒辦法完成業務,那么就需要好好考慮一下:這個長時間存活的對象,為什么必須要持有Activity的context。它設計的是否合理,是否它應該是一個長時間存活的對象(比如單例)。

尾聲

關于內存泄漏,還是需要咱們平時多注意,對自己寫的每一行代碼都多思考。畢竟這東西“不是病,但疼起來真要命”。

我是一個應屆生,最近和朋友們維護了一個公眾號,內容是我們在從應屆生過渡到開發這一路所踩過的坑,以及我們一步步學習的記錄,如果感興趣的朋友可以關注一下,一同加油~

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/7353.html

相關文章

  • 優秀代碼必知必會(一)?

    摘要:但由于模式本身有嚴重的缺陷,由于構造方法在多次調用中被分割,導致可能處于不一致的狀態,并且還需要額外增加工作以確保線程安全。方法必須遵從類指定的常規約定,將不同的哈希碼分配給不同的實例對象。 1.使用靜態工廠方法替代構造方法 靜態工廠方法的優點: 不像構造方法,它是有名字的。 它不需要每次調用時都創建一個新對象。 它可以返回 其返回類型的任何子類型的對象。 返回對象的類可以根...

    ChanceWong 評論0 收藏0
  • JavaScript中內存泄漏以及如何處理

    摘要:本文將會討論中的內存泄漏以及如何處理,方便大家在使用編碼時,更好的應對內存泄漏帶來的問題。當內存不再需要時進行釋放大部分內存泄漏問題都是在這個階段產生的,這個階段最難的問題就是確定何時不再需要已分配的內存。中的相同對象稱為全局。 隨著現在的編程語言功能越來越成熟、復雜,內存管理也容易被大家忽略。本文將會討論JavaScript中的內存泄漏以及如何處理,方便大家在使用JavaScript...

    itvincent 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<