编程知识 购物 网址 新闻 笑话 | 软件 日历 阅读 图书馆 China 头条阅读 学淘股 China Travel
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
   -> Android开发 -> Android内存泄漏监测(MAT)及解决办法 -> 正文阅读

[Android开发]Android内存泄漏监测(MAT)及解决办法

http://ttlnews.blogspot.com/2010/01/attacking-memory-problems-on-android.html 
这篇文章是2010年1月份写的,其中有些已经不适合现在的Android机制了 
我将内存问题分为两种:OOM和堆栈溢出 
一个Android进程可以分配的最大堆内存(heap memory)为 16M(现在各个定制版本的Android系统都不一样)
如果你将重复打开关闭一个Activity20次,就有可能出现内存溢出,那么在哪里内存溢出了,在哪里可以被GC回收? 
adb shell procrank 
使用这个命令可以获得一些应用的内存数据,但是只能获取很简单的数据 
adb shell dumpsys meminfo 
使用这个命令可以得到更多相关数据 
如果想要了解更多关于内存分配和回收的细节就需要 Eclipse Memory Analyzer Tool (MAT)工具。 
MAT工具使用方法:
http://kohlerm.blogspot.com/2009/04/analyzing-memory-usage-off-your-android.html 
http://blog.csdn.net/sgwhp/article/details/9842509
MAT可以显示的内容


最佳实践:
1.在onDestroy()中最好将匿名listeners都设置为null,比如view.setOnClickListener(null) ; 
2.即使没有静态drawable变量,但drawable对象中引用了view,view对象引用了Context,所以Activity可能会泄漏;
//Android源码片段   Drawable对象中引用View对象

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { 
public void setBackgroundDrawable(Drawable background) { 
..... 
background.setCallback(this); 
...... 
} 
} 

public abstract class Drawable { 
public final void setCallback(Callback cb) { 
mCallback = new WeakReference<Callback>(cb); 
} 
} 

所以最好在 onDestroy() 中调用view.getBackground().setCallback(null); 
在stackoverflow的相关问答中出现了通用的unbindDrawables方法 
http://stackoverflow.com/questions/9461364/exception-in-unbinddrawables 

@Override 
protected void onDestroy() 
{ 
super.onDestroy(); 
unbindDrawables(findViewById(R.id.top_layout)); 
System.gc(); 
Drawables(View view) 
{ 
if (view.getBackground() != null) 
{ 
view.getBackground().setCallback(null); 
view.setBackground(null); //添加
} 
if (view instanceof ViewGroup && !(view instanceof AdapterView)) 
{ 
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) 
{ 
unbindDrawables(((ViewGroup) view).getChildAt(i)); 
} 
((ViewGroup) view).removeAllViews(); 
} 
} 

【补充】上述方法对ListView和GridView无用
3. 在onDestroy()中设置object = null 虽然设置object = null不是必要的,但是可以让GC加快一点; 
4.让所有对象设置为null,虽然是很方便,但是也容易出错,最优的方法是通过MAT工具来监测哪些对象可能会泄漏,然后在 onDestroy()中置null。不然的话如果一个后台线程还在运行并且需要调用这些对象,那么就容易出现NullPointerExceptions。 
5.Images(Bitmaps)不像一般Java对象一样分配内存而是通过调用natvie方法,所以bitmap占用了非Dalvik堆的内存。所以使用MAT工具时会发现用procrank和dumpsys命令查看的内存会比MAT中的大很多。 
【补充】 
 摘自https://developer.android.com/training/displaying-bitmaps/manage-memory.html (翻译:) http://su1216.iteye.com/blog/1931629  
(1) Android2.2及之前版本,GC时应用的线程都会停止,这样会引起延迟,导致性能降低。所以在2.3中添加了并发GC机制,所以只要bitmap不再被引用,所占内存就马上会被回收。 
(2) 在2.3及之前版本,bitmap的像素数据是存储在native memory中的,并不是和bitmap对象一起存储在Dalvik heap里的,会导致native memory中的像素数据不能被显式回收,造成应用超出内存大小限制而崩溃。 
在2.3 (API level 11)之后的版本,像素数据就和bitmap对象一起存储在Dalvik heap上了。 
6.加载网络如片在Android中会比较难以操作,只是加载几个200x200像素的图片就会导致内存占用的暴涨,20k大小的200x200的png图片需要占用160K左右的内存(每个像素占用4bytes)[200x200x4/1024 = 156.25k ]
推荐使用下列方法【摘自 http://android-developers.blogspot.com/2008/09/android-photostream.html】 
(1) 首先获得图片的的大小(像素)

BitmapFactory.Options options = new BitmapFactory.Options(); 
//只加载图片的部分信息,减少内存占用   
options.inJustDecodeBounds = true; 
Bitmap tmpBitmap = BitmapFactory.decodeStream(new ByteArrayInputStream(new URL(url).openStream()), null, options); 
//获取图片的长宽像素   
int height = options.outHeight; 
int width = options.outWidth; 

(2) 这样就在下载网络图片之前就可以知道图片的大小了,然后根据最终需要显示的图片大小进行压缩(通常Android会在绘制的时候缩放图片) 

options = new BitmapFactory.Options(); 
options.inSampleSize = sampleSize;//压缩比列,如果是3,就会压缩到1/3 
bitmap = BitmapFactory.decodeStream(new ByteArrayInputStream(new URL(url).openStream()), null, options); 

这样获取的图片内存占用会小一点。 
(3) 更好的办法是将图片下载到本地,在使用的时候根据大小重新缩放。
将不再需要图片对象时调用bitmap.recyce()来释放掉图片的内存占用,但是如果你调用了recycle(),之后又试图绘制这个bitmap,你会得到 错误:“Canvas: trying to use a recycled bitmap”(适合Android2.3及之前版本)。 
7.ListView的convertView缓存方式 【网上资料很多】 
8.debug的时候会保持对象处于可用状态,内存不能被回收。所以内存分析(使用MAT工具)的时候不要使用debug。并且在heap dump之前多进行几次GC操作
【原因:http://groups.google.com/group/android-developers/browse_thread/thread/7b0ea57d9507d33f】 
文章的回复里有个问题 
问题: 
我写了一个简单的demo,只有两个activity,重复打开SecondActivity 6次,使用MAT工具查看内存发现有6个SecondActivity对象,为什么会这样? 
回答: 
可能导致上述问题的原因 
(1) 怎么打开和关闭SecondActivity的,是通过Intent吗?是通过硬件返回按钮关闭SecondActivity的吗? 
(2) 在SecondActivity中重载onDestroy(),打上log,重复打开SecondActivity 6次,onDestroy()中的log会打印6次吗? 
(3) 用多快速度重新打开和关闭SecondActivity的?最好是当看见一个GC log时再重新打开,可能是还没有来得及GC,所以内存中会有多个对象(可有可能是你的demo内存占用太小,没有达到需要GC的条件) 
(4)检查一下6个SecondActivity对象的状态是否为unknown,MAT也会统计unkown状态的对象。【补充:可以使用adb shell dumpsys meminfo 命令查看当前内存中Activity存在的数目】 
  Android开发 最新文章
Android动态权限申请
使用Kotlin,抛弃findViewById
.net程序员做的第一个安卓APP
Android学习笔记
计算机毕业设计源码分享
计算机毕业设计源码分享
ELF Format 笔记(一)—— 概述
Fragment学习笔记
Android复制Assets目录下的文件到指定目录
Android网络请求框架AsyncHttpClient实例详
上一篇文章      下一篇文章      查看所有文章
加:2015-03-30 07:50:33  更:2017-05-16 20:14:17 
 
360图书馆 软件开发资料 购物精选 新闻资讯 Chinese Culture 三丰软件 开发 中国文化 阅读网 头条阅读 学淘股 China Travel 日历 万年历 2020年7日历
2020-7-6 17:38:15
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  编程知识