導航:首頁 > 操作系統 > android內存泄漏

android內存泄漏

發布時間:2022-03-14 21:38:17

android內存泄露怎麼解決

從谷歌的Android 5.0.1系統開始,就有用戶反應存在內存泄漏問題,而在最新版本的Android 5.1更新來看,谷歌似乎並沒有解決這個問題,這讓許多用戶感到非常不滿。不過現在從谷歌的AOSP網站來看,似乎已經計劃著手解決這個問題,預計會在下次Android 5.1.1更新時到來。 最近包括許多用戶反映Android 5.1上Google+等應用會自動重啟,某些應用在使用時還會自動退出,導致內存佔用率大幅上升,大約會佔用750MB到800MB左右。還有用戶稱打開應用後內存佔用率會上升,但關掉應用後系統卻不會空出多餘內存。而目前許多Nexus 5用戶都表示遇到了這個問題。 看來,現在遇到內存泄漏問題的用戶還需要再耐性等待一段時間,等到谷歌發布Android 5.1.1更新才行了。

② android byte數組為什麼會內存泄漏

內存泄露 memory leak,是指程序在申請內存後,無法釋放已申請的內存空間,可以使用軟引用,如果內存空間不足了,就會回收這些對象的內存

③ Android 內存泄露的壞處

用戶對單次的內存泄漏並沒有什麼感知,但當泄漏積累到內存都被消耗完,就會導致卡頓,崩潰。
內存泄露是內存溢出OOM的重要原因之一,會導致Crash

④ 如何避免Android內存泄漏

這個是沒法避免的,安卓本身就不是密封的系統,而是開放的。
但是,可以通過以下的手段來實現保密。

1、手機不root,病毒無法入侵系統根本性文件,也就無法提取內存。
2、手機root以後,安裝360、LBE安全大師等的軟體,利用主動防禦,也可以實現保密。
3、不訪問以下危險網站、黃網等等的。
4、通過應用商店下載軟體,而非第三方途徑的軟體。
5、手機定期清理垃圾、殺毒等。
6、各個應用程序的許可權設置都為使用時詢問,這樣也可以有效的避免自己的隱私泄露。

⑤ 如何檢查android 內存泄漏

1. 查詢資料庫而沒有關閉Cursor 在Android中,Cursor是很常用的一個對象,但在寫代碼是,經常會有人忘記調用close, 或者因為代碼邏輯問題狀況導致close未被調用。 通常,在Activity中,我們可以調用startManagingCursor或直接使用managedQuery讓...

⑥ 導致android內存泄漏原因有哪些

Android應用內存泄漏的的原因有以下幾個:
1查詢資料庫後沒有關閉游標cursor
2 構造Adapter時,沒有使用 convertView 重用
3 Bitmap對象不在使用時調用recycle()釋放內存
4 對象被生命周期長的對象引用,如activity被靜態集合引用導致activity不能釋放

內存泄漏的發現:
通過DDMS中的heap工具,去發現是否有內存溢出。

內存泄漏如何解決:
通過內存分析工具 MAT(Memory Analyzer Tool),找到內存泄露的對象

⑦ android開發什麼叫內存泄露

下面圖片是解決內存泄露的例子。例子來自android學習手冊,android學習手冊,裡面有源碼。android學習手冊包含9個章節,108個例子,源碼文檔隨便看,例子都是可交互,可運行,源碼採用android studio目錄結構,高亮顯示代碼,文檔都採用文檔結構圖顯示,可以快速定位。360手機助手中下載,圖標上有貝殼

在android程序開發中,當一個對象已經不需要再使用了,本該被回收時,而另外一個正在使用的對象持有它的引用從而導致它不能被回收,這就導致本該被回收的對象不能被回收而停留在堆內存中,內存泄漏就產生了。

內存泄漏有什麼影響呢?它是造成應用程序OOM的主要原因之一。由於android系統為每個應用程序分配的內存有限,當一個應用中產生的內存泄漏比較多時,就難免會導致應用所需要的內存超過這個系統分配的內存限額,這就造成了內存溢出而導致應用Crash。

了解了內存泄漏的原因及影響後,我們需要做的就是掌握常見的內存泄漏,並在以後的android程序開發中,盡量避免它。下面小編搜羅了5個android開發中比較常見的內存泄漏問題及解決辦法,分享給大家,一起來看看吧。

一、單例造成的內存泄漏

Android的單例模式非常受開發者的喜愛,不過使用的不恰當的話也會造成內存泄漏。因為單例的靜態特性使得單例的生命周期和應用的生命周期一樣長,這就說明了如果一個對象已經不需要使用了,而單例對象還持有該對象的引用,那麼這個對象將不能被正常回收,這就導致了內存泄漏。

如下這個典例:

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;

}

}

這是一個普通的單例模式,當創建這個單例的時候,由於需要傳入一個Context,所以這個Context的生命周期的長短至關重要:

1、傳入的是Application的Context:這將沒有任何問題,因為單例的生命周期和Application的一樣長 ;

2、傳入的是Activity的Context:當這個Context所對應的Activity退出時,由於該Context和Activity的生命周期一樣長(Activity間接繼承於Context),所以當前Activity退出時它的內存並不會被回收,因為單例對象持有該Activity的引用。

所以正確的單例應該修改為下面這種方式:

public class AppManager {

private static AppManager instance;

private Context context;

private AppManager(Context context) {

this.context = context.getApplicationContext();

}

public static AppManager getInstance(Context context) {

if (instance != null) {

instance = new AppManager(context);

}

return instance;

}

}

這樣不管傳入什麼Context最終將使用Application的Context,而單例的生命周期和應用的一樣長,這樣就防止了內存泄漏。

二、非靜態內部類創建靜態實例造成的內存泄漏

有的時候我們可能會在啟動頻繁的Activity中,為了避免重復創建相同的數據資源,會出現這種寫法:

public class MainActivity extends AppCompatActivity {

private static TestResource mResource = null;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

if(mManager == null){

mManager = new TestResource();

}

//...

}

class TestResource {

//...

}

}

這樣就在Activity內部創建了一個非靜態內部類的單例,每次啟動Activity時都會使用該單例的數據,這樣雖然避免了資源的重復創建,不過這種寫法卻會造成內存泄漏,因為非靜態內部類默認會持有外部類的引用,而又使用了該非靜態內部類創建了一個靜態的實例,該實例的生命周期和應用的一樣長,這就導致了該靜態實例一直會持有該Activity的引用,導致Activity的內存資源不能正常回收。正確的做法為:

將該內部類設為靜態內部類或將該內部類抽取出來封裝成一個單例,如果需要使用Context,請使用ApplicationContext 。

三、Handler造成的內存泄漏

Handler的使用造成的內存泄漏問題應該說最為常見了,平時在處理網路任務或者封裝一些請求回調等api都應該會藉助Handler來處理,對於Handler的使用代碼編寫一不規范即有可能造成內存泄漏,如下示例:

public class MainActivity extends AppCompatActivity {

private Handler mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

//...

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

loadData();

}

private void loadData(){

//...request

Message message = Message.obtain();

mHandler.sendMessage(message);

}

}

這種創建Handler的方式會造成內存泄漏,由於mHandler是Handler的非靜態匿名內部類的實例,所以它持有外部類Activity的引用,我們知道消息隊列是在一個Looper線程中不斷輪詢處理消息,那麼當這個Activity退出時消息隊列中還有未處理的消息或者正在處理消息,而消息隊列中的Message持有mHandler實例的引用,mHandler又持有Activity的引用,所以導致該Activity的內存資源無法及時回收,引發內存泄漏,所以另外一種做法為:

public class MainActivity extends AppCompatActivity {

private MyHandler mHandler = new MyHandler(this);

private TextView mTextView ;

private static class MyHandler extends Handler {

private WeakReference<Context> reference;

public MyHandler(Context context) {

reference = new WeakReference<>(context);

}

@Override

public void handleMessage(Message msg) {

MainActivity activity = (MainActivity) reference.get();

if(activity != null){

activity.mTextView.setText("");

}

}

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mTextView = (TextView)findViewById(R.id.textview);

loadData();

}

private void loadData() {

//...request

Message message = Message.obtain();

mHandler.sendMessage(message);

}

}

創建一個靜態Handler內部類,然後對Handler持有的對象使用弱引用,這樣在回收時也可以回收Handler持有的對象,這樣雖然避免了Activity泄漏,不過Looper線程的消息隊列中還是可能會有待處理的消息,所以我們在Activity的Destroy時或者Stop時應該移除消息隊列中的消息,更准確的做法如下:

public class MainActivity extends AppCompatActivity {

private MyHandler mHandler = new MyHandler(this);

private TextView mTextView ;

private static class MyHandler extends Handler {

private WeakReference<Context> reference;

public MyHandler(Context context) {

reference = new WeakReference<>(context);

}

@Override

public void handleMessage(Message msg) {

MainActivity activity = (MainActivity) reference.get();

if(activity != null){

activity.mTextView.setText("");

}

}

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mTextView = (TextView)findViewById(R.id.textview);

loadData();

}

private void loadData() {

//...request

Message message = Message.obtain();

mHandler.sendMessage(message);

}

@Override

protected void onDestroy() {

super.onDestroy();

mHandler.removeCallbacksAndMessages(null);

}

}

使用mHandler.removeCallbacksAndMessages(null);是移除消息隊列中所有消息和所有的Runnable。當然也可以使用mHandler.removeCallbacks();或mHandler.removeMessages();來移除指定的Runnable和Message。

四、線程造成的內存泄漏

對於線程造成的內存泄漏,也是平時比較常見的,如下這兩個示例可能每個人都這樣寫過:

//——————test1

new AsyncTask<Void, Void, Void>() {

@Override

protected Void doInBackground(Void... params) {

SystemClock.sleep(10000);

return null;

}

}.execute();

//——————test2

new Thread(new Runnable() {

@Override

public void run() {

SystemClock.sleep(10000);

}

}).start();

上面的非同步任務和Runnable都是一個匿名內部類,因此它們對當前Activity都有一個隱式引用。如果Activity在銷毀之前,任務還未完成, 那麼將導致Activity的內存資源無法回收,造成內存泄漏。正確的做法還是使用靜態內部類的方式,如下:

static class MyAsyncTask extends AsyncTask<Void, Void, Void> {

private WeakReference<Context> weakReference;

public MyAsyncTask(Context context) {

weakReference = new WeakReference<>(context);

}

@Override

protected Void doInBackground(Void... params) {

SystemClock.sleep(10000);

return null;

}

@Override

protected void onPostExecute(Void aVoid) {

super.onPostExecute(aVoid);

MainActivity activity = (MainActivity) weakReference.get();

if (activity != null) {

//...

}

}

}

static class MyRunnable implements Runnable{

@Override

public void run() {

SystemClock.sleep(10000);

}

}

//——————

new Thread(new MyRunnable()).start();

new MyAsyncTask(this).execute();

這樣就避免了Activity的內存資源泄漏,當然在Activity銷毀時候也應該取消相應的任務AsyncTask::cancel(),避免任務在後台執行浪費資源。

五、資源未關閉造成的內存泄漏

對於使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源的使用,應該在Activity銷毀時及時關閉或者注銷,否則這些資源將不會被回收,造成內存泄漏。

⑧ android有哪些具體的情形會導致內存泄漏

集合類泄漏
集合類如果僅僅有添加元素的方法,而沒有相應的刪除機制,導致內存被佔用。如果這個集合類是全局性的變數 (比如類中的靜態屬性,全局性的 map 等即有靜態引用或 final 一直指向它),那麼沒有相應的刪除機制,很可能導致集合所佔用的內存只增不減。比如上面的典型例子就是其中一種情況,當然實際上我們在項目中肯定不會寫這么 2B 的代碼,但稍不注意還是很容易出現這種情況,比如我們都喜歡通過 HashMap 做一些緩存之類的事,這種情況就要多留一些心眼。
單例造成的內存泄漏
由於單例的靜態特性使得其生命周期跟應用的生命周期一樣長,所以如果使用不恰當的話,很容易造成內存泄漏
匿名內部類/非靜態內部類和非同步線程
非靜態內部類創建靜態實例造成的內存泄漏
有的時候我們可能會在啟動頻繁的Activity中,為了避免重復創建相同的數據資源
Handler 造成的內存泄漏
Handler 的使用造成的內存泄漏問題應該說是最為常見了,很多時候我們為了避免 ANR 而不在主線程進行耗時操作,在處理網路任務或者封裝一些請求回調等api都藉助Handler來處理,但 Handler 不是萬能的,對於 Handler 的使用代碼編寫一不規范即有可能造成內存泄漏。另外,我們知道 Handler、Message 和 MessageQueue 都是相互關聯在一起的,萬一 Handler 發送的 Message 尚未被處理,則該 Message 及發送它的 Handler 對象將被線程 MessageQueue 一直持有。
由於 Handler 屬於 TLS(Thread Local Storage) 變數, 生命周期和 Activity 是不一致的。因此這種實現方式一般很難保證跟 View 或者 Activity 的生命周期保持一致,故很容易導致無法正確釋放。

⑨ android 內存泄露 會導致什麼問題

1. 查詢資料庫而沒有關閉Cursor
在Android中,Cursor是很常用的一個對象,但在寫代碼是,經常會有人忘記調用close, 或者因為代碼邏輯問題狀況導致close未被調用。
通常,在Activity中,我們可以調用startManagingCursor或直接使用managedQuery讓Activity自動管理Cursor對象。
但需要注意的是,當Activity介紹後,Cursor將不再可用!
若操作Cursor的代碼和UI不同步(如後台線程),那沒需要先判斷Activity是否已經結束,或者在調用OnDestroy前,先等待後台線程結束。
除此之外,以下也是比較常見的Cursor不會被關閉的情況:
雖然表面看起來,Cursor.close()已經被調用,但若出現異常,將會跳過close(),從而導致內存泄露。
所以,我們的代碼應該以如下的方式編寫:
Cursor c = queryCursor();
try {
int a = c.getInt(1);
......
} catch (Exception e) {
} finally {
c.close(); //在finally中調用close(), 保證其一定會被調用
}
try {
Cursor c = queryCursor();
int a = c.getInt(1);
......
c.close();
} catch (Exception e) {
}
2. 調用registerReceiver後未調用unregisterReceiver().
在調用registerReceiver後,若未調用unregisterReceiver,其所佔的內存是相當大的。
而我們經常可以看到類似於如下的代碼:
這是個很嚴重的錯誤,因為它會導致BroadcastReceiver不會被unregister而導致內存泄露。
registerReceiver(new BroadcastReceiver() {
...
}, filter); ...

3. 未關閉InputStream/OutputStream

在使用文件或者訪問網路資源時,使用了InputStream/OutputStream也會導致內存泄露
4. Bitmap使用後未調用recycle()
根據SDK的描述,調用recycle並不是必須的。但在實際使用時,Bitmap佔用的內存是很大的,所以當我們不再使用時,盡量調用recycle()以釋放資源。
5. Context泄露
這是一個很隱晦的內存泄露的情況。
先讓我們看一下以下代碼:
在這段代碼中,我們使用了一個static的Drawable對象。
這通常發生在我們需要經常調用一個Drawable,而其載入又比較耗時,不希望每次載入Activity都去創建這個Drawable的情況。
此時,使用static無疑是最快的代碼編寫方式,但是其也非常的糟糕。
當一個Drawable被附加到View時,這個View會被設置為這個Drawable的callback (通過調用Drawable.setCallback()實現)。
這就意味著,這個Drawable擁有一個TextView的引用,而TextView又擁有一個Activity的引用。
這就會導致Activity在銷毀後,內存不會被釋放。
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}

⑩ Android 內存溢出和內存泄漏的區別

內存溢出是指當對象的內存佔用已經超出分配內存的空間大小,這時未經處理的異常就會拋出。比如常見的內存溢出情況有:bitmap過大;引用沒釋放;資源對象沒關閉
如圖,這是常見的bitma對象的溢出,顯示像素過高或圖片尺寸遠遠大於顯示空間的尺寸時,通常都要將其縮放,減小佔用內存。
內存泄漏(memory
leak)
有些對象只有有限的生命周期。當它們的任務完成之後,它們將被垃圾回收。如果在對象的生命周期本該結束的時候,這個對象還被一系列的引用,這就會導致內存泄漏。隨著泄漏的累積,app將消耗完內存。
比如,在Activity.onDestroy()被調用之後,view樹以及相關的bitmap都應該被垃圾回收。如果一個正在運行的後台線程繼續持有這個Activity的引用,那麼相關的內存將不會被回收,這最終將導致OutOfMemoryError崩潰。
memory
leak會最終會導致out
of
memory!
如圖,這是使用MAT工具查找內存泄漏的結果,例子是
handle
延時發送
message
而在關閉
activity

context
被銷毀所引發的泄漏,這是作為目的性的測試所以問題比較容易找到,在實際開發中內存泄漏不易察覺並難以找到,當泄漏累積到一定程度是會引發
OOM
的。

閱讀全文

與android內存泄漏相關的資料

熱點內容
pdf林徽因傳 瀏覽:527
國產區小電影網址 瀏覽:102
西班牙大尺度男男 瀏覽:609
消先的眼角膜電影 瀏覽:434
編譯原理課設項目簡介 瀏覽:921
日本《失樂園》無刪減 瀏覽:227
更新最快的電視劇網站 瀏覽:597
啟動app的廣告怎麼關 瀏覽:850
非sp文中的sp情節的小說 瀏覽:76
女主是被拐賣到大山的小說 瀏覽:858
哆啦a夢美人魚電影 瀏覽:597
舊版本蝌蚪短視頻app怎麼不能 瀏覽:458
電影劇情里有個老頭在雨里騎單車有防 瀏覽:950
日本歐美推理片電影 瀏覽:75
主角穿越到紅軍長征 瀏覽:915
《屍吻》拿走不謝 瀏覽:306
日本重生電影最後主角死了沒 瀏覽:137
愛奇電影大全 瀏覽:373
cf美國伺服器如何下載 瀏覽:152
linux後退命令 瀏覽:901