日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android中内存泄露,Android中的内存泄露

發布時間:2024/10/8 Android 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android中内存泄露,Android中的内存泄露 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

編輯推薦:

本文來自于csdn,本文主要從java的內存模型講起,最終舉出幾個內存泄露的例子和解決方案。

java運行時內存模型

具體信息:http://gityuan.com/2016/01/09/java-memory/

回收算法

JVM回收算法主要有兩種

1.引用計數法:每個對象有一個引用計數器,當對象被引用一次時計數器加一,引用失效計數器減一。當計數器為0時表示對象可以被回收。(由于無法解決相互引用問題而被廢棄)

2.可達性算法:從GC ROOT節點開始遍歷,可以連通的對象都是活對象。無法到達的對象可以被回收。

可以作為GC ROOT節點的對象

虛擬機棧的棧幀的局部變量表引用的對象

本地方法棧JNI引用的對象

方法區的靜態變量和常量所引用的對象

例子

public

class GCDemo {

public static void main(String[] args) {

GcObject obj1 = new GcObject();

GcObject obj2 = new GcObject();

obj1.instance = obj2;

obj2.instance = obj1;

obj1 = null;

obj2 = null;

}

}

class GcObject {

public Object instance = null;

}

引用計數法內存圖

1.step1:GcObject實例1的引用計數+1,目前為1

2.step2:GcObject實例2的引用計數+1,目前為1

3.step3:GcObject實例2的引用計數+1,目前為2

4.step4:GcObject實例1的引用計數+1,目前為2

5.obj1 = null:GcObject實例1引用計數-1,目前為1

6.obj2 = null:GcObject實例2引用計數-1,目前為1

到此為止,GcObject實例1和2都無法使用,但是引用計數不為0,發生內存泄露。

可達性算法內存圖

由可以被作為GC ROOT對象來看,虛擬機棧中obj1和obj2是兩個GC ROOT起點,由于最終都將obj1與obj2設置為了null。因此GcObject1和2都無法可達,因此可以被回收。

在Java中,內存泄漏就是存在一些被分配的對象,這些對象有下面兩個特點,首先,這些對象是可達的,即在有向圖中,存在通路可以與其相連;其次,這些對象是無用的,即程序以后不會再使用這些對象。如果對象滿足這兩個條件,這些對象就可以判定為Java中的內存泄漏,這些對象不會被GC所回收,然而它卻占用內存。

Android中常見的內存泄露

Android中最常見的內存泄露是關于Activity的內存泄漏。其核心問題在于在Activity生命周期之外仍有其引用。從內存模型角度來講,它在GC

ROOTING時可達,但是它的onDestroy已經被執行。既它從我們期待的行為上來說應該被標識為可以被回收。但它仍然可達。以下就列出最常見的幾種情況,請記住核心矛盾:Activity生命周期之外仍有其引用

Handler導致的內存泄漏

public

class SampleActivity extends Activity {

private final Handler mLeakyHandler = new

Handler() {

@Override

public void handleMessage(Message msg) {

// ...

}

}

@Override

protected void onCreate(Bundle savedInstanceState)

{

super.onCreate(savedInstanceState);

// 延時10分鐘發送一個消息

mLeakyHandler.postDelayed(new Runnable() {

@Override

public void run() { }

}, 60 * 10 * 1000);

// 返回前一個Activity

finish();

}

}

思考上面代碼,它會發生嚴重的內存泄露。首先,mLeakyHandler被聲明為了一個匿名內部類(自己思考,上述代碼有幾個匿名內部類),它隱式的持有了外部類Activity的強引用。之后,handler發出了一個10分鐘的延時消息,接著Activity殺掉了自己。問題的關鍵在于handler發出的消息Message會在消息隊列里存i在10分鐘。它持有發出消息的handler的引用。而handler又持有Activity的強引用。這就導致Activity在其生命周期之外仍有強引用,發生了嚴重的內存泄露。

注意,問題的核心在于內部類以及匿名內部類都會隱式的持有外部類的強引用。這就導致一個類的生命不在由一個因素控制,變為了多個因素。在我們認為該結束的時候而沒有產生正確的行為。解決的方案很簡單,也很通用:

用靜態內部類。

在靜態內部類根據需求使用弱引用修飾需要引用的外部類資源。

public

class SampleActivity extends Activity {

/**

* 匿名類的靜態實例不會隱式持有他們外部類的引用

*/

private static final Runnable sRunnable = new

Runnable() {

@Override

public void run() {

}

};

private final MyHandler mHandler = new MyHandler(this);

@Override

protected void onCreate(Bundle savedInstanceState)

{

super.onCreate(savedInstanceState);

// 延時10分鐘發送一個消息.

mHandler.postDelayed(sRunnable, 60 * 10 * 1000);

// 返回前一個Activity

finish();

}

/**

* 靜態內部類的實例不會隱式持有他們外部類的引用。

*/

private static class MyHandler extends Handler

{

private final WeakReference

mActivity;

public MyHandler(SampleActivity activity)

{

mActivity = new WeakReference(activity);

}

@Override

public void handleMessage(Message msg) {

SampleActivity activity = mActivity.get();

if (activity != null) {

// ...

}

}

}

}

static變量導致的內存泄漏

static變量在進程啟動的時候被分配內存空間。在進程被殺死的時候釋放內存空間。因此,它的生命周期是貫穿整個應用的生命周期的。也就是說,當你的Activity被靜態變量染指到。那么又會導致Activity在其生命周期之外仍有強引用,發生內存泄露。

常見的場景如下:

static

Context

static View

兩者的本質是一樣的,因為View內部持有Context的引用。第一種最常見的就是單例模式的實現,將具體的Activity的Context傳遞進去構造單例對象,導致泄露。第二種是當View需要加載的資源比較大時,想一勞永逸。而產生內存泄露。

解決方法依然通用且簡單,在Activity聲明周期外使用Context盡量去使用Application的Context

Activiity內部聲明的靜態資源要及時釋放, 在相應的聲明周期方法中做好收尾工作

注冊與解注冊

在andorid開發中,我們經常會在Activity的onCreate中注冊廣播接受器、EventBus等,如果忘記成對的使用反注冊,可能會引起內存泄漏。開發過程中應該養成良好的相關,在onCreate或onResume中注冊,要記得相應的在onDestroy或onPause中反注冊。

創建與關閉

在android中,資源性對象比如Cursor、File、Bitmap、視頻等,系統都用了一些緩沖技術,在使用這些資源的時候,如果我們確保自己不再使用這些資源了,要及時關閉,否則可能引起內存泄漏。因為有些操作不僅僅只是涉及到Dalvik虛擬機,還涉及到底層C/C++等的內存管理,不能完全寄希望虛擬機幫我們完成內存管理。

在這些資源不使用的時候,記得調用相應的類似close()、destroy()、recycler()、release()等函數,這些函數往往會通過jni調用底層C/C++的相應函數,完成相關的內存釋放。

Cursor對象及時關閉

IO對象及時關閉

集合造成的內存泄漏

Vector

v = new Vector(10);

for (int i = 1; i < 100; i++) {

Object o = new Object();

v.add(o);

o = null;

}

畫個簡單的內存圖就可以看出在棧中分配的v指向了在堆中分配的十個空間,雖然每次置為null,但是將V作為GC

ROOT的起點仍然可達每一個在堆中的Object對象,而我們本意是將每一個Object對象置為了null。

解決方案很簡單:v = null 。本質上是斷掉GC ROOT的起點。

總結

以上是生活随笔為你收集整理的android中内存泄露,Android中的内存泄露的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。