qq红包扫雷挂怎么设置金额

12 / 12 页
Android 性能优化之使用MAT分析内存泄露问题
TA的每日心情怒 16:30签到天数: 2 天连续签到: 1 天[LV.1]初来乍到帖子交易币下载币
小有名气, 积分 163, 距离下一级还需 37 积分
小有名气, 积分 163, 距离下一级还需 37 积分
发表于 4&天前
感谢楼主,万岁
TA的每日心情擦汗 13:12签到天数: 6 天连续签到: 1 天[LV.2]偶尔看看I帖子交易币下载币
名动一方, 积分 306, 距离下一级还需 94 积分
名动一方, 积分 306, 距离下一级还需 94 积分
发表于 3&天前
厉害厉害学习一下哈
TA的每日心情擦汗 00:16签到天数: 1 天连续签到: 1 天[LV.1]初来乍到帖子交易币下载币
名动一方, 积分 203, 距离下一级还需 197 积分
名动一方, 积分 203, 距离下一级还需 197 积分
发表于 3&天前
起易有你更精彩
该用户从未签到帖子交易币下载币
小有名气, 积分 99, 距离下一级还需 101 积分
小有名气, 积分 99, 距离下一级还需 101 积分
发表于 前天&11:18
谢谢楼主分享!!
该用户从未签到帖子交易币下载币
编程初步, 积分 3, 距离下一级还需 27 积分
编程初步, 积分 3, 距离下一级还需 27 积分
发表于 前天&16:52
加油!!!!!!!!!!!!!!!!!!!
TA的每日心情开心 01:02签到天数: 1 天连续签到: 1 天[LV.1]初来乍到帖子交易币下载币
小有名气, 积分 102, 距离下一级还需 98 积分
小有名气, 积分 102, 距离下一级还需 98 积分
发表于 前天&19:56
谢谢楼主分享!!
该用户从未签到帖子交易币下载币
编程初步, 积分 0, 距离下一级还需 30 积分
编程初步, 积分 0, 距离下一级还需 30 积分
发表于 前天&20:40
谢谢楼主分享!!
该用户从未签到帖子交易币下载币
编程初步, 积分 0, 距离下一级还需 30 积分
编程初步, 积分 0, 距离下一级还需 30 积分
发表于 昨天&12:48
小学生的福音
该用户从未签到帖子交易币下载币
编程初步, 积分 6, 距离下一级还需 24 积分
编程初步, 积分 6, 距离下一级还需 24 积分
发表于 8&小时前
小学生的福音
TA的每日心情开心 09:17签到天数: 4 天连续签到: 1 天[LV.2]偶尔看看I帖子交易币下载币
名动一方, 积分 378, 距离下一级还需 22 积分
名动一方, 积分 378, 距离下一级还需 22 积分
发表于 2&小时前
厉害厉害学习一下哈
12 / 12 页
站长推荐 /1
线上/实地 招聘:易语言、IOS逆向、PHP、WEB前端、C++ 等讲师,有能力者请联系:QQ:。固定工资待遇丰厚,添加时请注明来意。
Powered byAndroid内存泄露调试分享 - 花郎 - ITeye技术网站
博客分类:
各位兄弟姐妹,Java开发中的内存泄露的问题经常会给我们带来很多烦恼。特别是对一些新手,如果平时不注意一些细节问题,最后很可能会导致很严重的后果。
在Android中的Java开发也同样会有这样的问题。附件中的pdf整理了一些关于Android中的Java开发,在内存使用方面需要注意的一些问题,希望能够对大家有所帮助。
Android 内存泄漏调试
Java编程中经常容易被忽视,但本身又十分重要的一个问题就是内存使用的问题。应用主要使用语言编写,因此这个问题也同样会在开发中出现。本文不对编程问题做探讨,而是对于在中,特别是应用开发中的此类问题进行整理。
由于作者接触时间并不是很长,因此如有叙述不当之处,欢迎指正。
二、中常见的容易引起内存泄漏的不良代码
Android主要应用在嵌入式设备当中,而嵌入式设备由于一些众所周知的条件限制,通常都不会有很高的配置,特别是内存是比较有限的。如果我们编写的代码当中有太多的对内存使用不当的地方,难免会使得我们的设备运行缓慢,甚至是死机。为了能够使得应用程序安全且快速的运行,的每个应用程序都会使用一个专有的虚拟机实例来运行,它是由服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运行的。一方面,如果程序在运行过程中出现了内存泄漏的问题,仅仅会使得自己的进程被掉,而不会影响其他进程(如果是等系统进程出问题的话,则会引起系统重启)。另一方面为不同类型的进程分配了不同的内存使用上限,如果应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被掉。为应用进程分配的内存上限如下所示:
位置: 部分脚本
# Define the oom_adj values for the classes of processes that can be
# killed by the kernel.
These are used in ActivityManagerService.
setprop ro.FOREGROUND_APP_ADJ 0
setprop ro.VISIBLE_APP_ADJ 1
setprop ro.SECONDARY_SERVER_ADJ 2
setprop ro.BACKUP_APP_ADJ 2
setprop ro.HOME_APP_ADJ 4
setprop ro.HIDDEN_APP_MIN_ADJ 7
setprop ro.CONTENT_PROVIDER_ADJ 14
setprop ro.EMPTY_APP_ADJ 15
# Define the memory thresholds at which the above process classes will
# be killed.
These numbers are in pages (4k).
setprop ro.FOREGROUND_APP_MEM 1536
setprop ro.VISIBLE_APP_MEM 2048
setprop ro.SECONDARY_SERVER_MEM 4096
setprop ro.BACKUP_APP_MEM 4096
setprop ro.HOME_APP_MEM 4096
setprop ro.HIDDEN_APP_MEM 5120
setprop ro.CONTENT_PROVIDER_MEM 5632
setprop ro.EMPTY_APP_MEM 6144
# Write value must be consistent with the above properties.
# Note that the driver only supports 6 slots, so we have HOME_APP at the
# same memory level as services.
write /sys/module/lowmemorykiller/parameters/adj 0,1,2,7,14,15
write /proc/sys/vm/overcommit_memory 1
write /proc/sys/vm/min_free_order_shift 4
write /sys/module/lowmemorykiller/parameters/minfree 96,44
# Set init its forked children's oom_adj.
write /proc/1/oom_adj -16
正因为我们的应用程序能够使用的内存有限,所以在编写代码的时候需要特别注意内存使用问题。如下是一些常见的内存使用不当的情况。
(一) 查询数据库没有关闭游标
程序中经常会进行查询数据库的操作,但是经常会有使用完毕后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。
示例代码:
Cursor cursor = getContentResolver().query(uri ...);
if (cursor.moveToNext()) {
修正示例代码:
Cursor cursor =
cursor = getContentResolver().query(uri ...);
if (cursor != null && cursor.moveToNext()) {
} finally {
if (cursor != null) {
cursor.close();
} catch (Exception e) {
//ignore this
(二) 构造Adapter时,没有使用缓存的 convertView
以构造的为例,在中提高了方法:
public View getView(int position, View convertView, ViewGroup parent)
来向提供每一个所需要的对象。初始时会从中根据当前的屏幕布局实例化一定数量的对象,同时会将这些对象缓存起来。当向上滚动时,原先位于最上面的的对象会被回收,然后被用来构造新出现的最下面的。这个构造过程就是由方法完成的,的第二个形参 就是被缓存起来的的对象初始化时缓存中没有对象则是。
由此可以看出,如果我们不去使用,而是每次都在中重新实例化一个对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。回收的对象的过程可以查看
android.widget.AbsListView.java --& void addScrapView(View scrap) 方法。
示例代码:
public View getView(int position, View convertView, ViewGroup parent) {
View view = new Xxx(...);
修正示例代码:
public View getView(int position, View convertView, ViewGroup parent) {
View view =
if (convertView != null) {
view = convertV
populate(view, getItem(position));
view = new Xxx(...);
(三) Bitmap对象不在使用时调用recycle()释放内存
有时我们会手工的操作对象,如果一个对象比较占内存,当它不在被使用的时候,可以调用方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。可以看一下代码中的注释:
* Free up the memory associated with this bitmap's pixels, and mark the
* bitmap as "dead", meaning it will throw an exception if getPixels() or
* setPixels() is called, and will draw nothing. This operation cannot be
* reversed, so it should only be called if you are sure there are no
* further uses for the bitmap. This is an advanced call, and normally need
* not be called, since the normal GC process will free up this memory when
* there are no more references to this bitmap.
(四) 释放对象的引用
这种情况描述起来比较麻烦,举两个例子进行说明。
假设有如下操作
public class DemoActivity extends Activity {
private Handler mHandler = ...
public void operation() {
obj = initObj();
mHandler.post(new Runnable() {
public void run() {
useObj(obj);
我们有一个成员变量 ,在中我们希望能够将处理实例的操作到某个线程的中。在以上的代码中,即便是所在的线程使用完了所引用的对象,但这个对象仍然不会被垃圾回收掉,因为还保有这个对象的引用。所以如果在中不再使用这个对象了,可以在的位置释放对象的引用,而代码可以修改为:
public void operation() {
obj = initObj();
final Object o =
mHandler.post(new Runnable() {
public void run() {
useObj(o);
假设我们希望在锁屏界面中,监听系统中的电话服务以获取一些信息如信号强度等,则可以在中定义一个的对象,同时将它注册到服务中。对于对象,当需要显示锁屏界面的时候就会创建一个对象,而当锁屏界面消失的时候对象就会被释放掉。
但是如果在释放对象的时候忘记取消我们之前注册的对象,则会导致无法被垃圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大量的对象没有办法被回收而引起使得进程挂掉。
总之当一个生命周期较短的对象,被一个生命周期较长的对象保有其引用的情况下,在的生命周期结束时,要在中清除掉对的引用。
Android应用程序中最典型的需要注意释放资源的情况是在的生命周期中,在、、方法中需要适当的释放资源的情况。由于此情况很基础,在此不详细说明,具体可以查看官方文档对生命周期的介绍,以明确何时应该释放哪些资源。
三、内存监测工具
无论怎么小心,想完全避免是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方。中的就带有一个很不错的内存监测工具这里我使用的插件,并以真机为例,在模拟器中的情况类似。用监测应用进程使用内存情况的步骤如下:
1. 启动后,切换到透视图,并确认视图、视图都是打开的;
2. 将手机通过链接至电脑,链接时需要确认手机是处于“调试”模式,而不是作为“”;
3. 链接成功后,在的视图中将会显示手机设备的序列号,以及设备中正在运行的部分进程信息;
4. 点击选中想要监测的进程,比如进程;
5. 点击选中视图界面中最上方一排图标中的“”图标;
6. 点击视图中的“”按钮;
7. 此时在视图中就会看到当前选中的进程的内存使用量的详细情况[如图所示]。
a) 点击“”按钮相当于向虚拟机请求了一次操作;
b) 当内存使用信息第一次显示以后,无须再不断的点击“”,视图界面会定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化;
c) 内存使用信息的各项参数根据名称即可知道其意思,在此不再赘述。
如何才能知道我们的程序是否有内存泄漏的可能性呢。这里需要注意一个值:视图中部有一个叫做,即数据对象,也就是我们的程序中大量存在的类类型的对象。在一行中有一列是“”,其值就是当前进程中所有数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。可以这样判断:
a) 不断的操作当前应用,同时注意观察的值;
b) 正常情况下值都会稳定在一个有限的范围内,也就是说由于程序中的的代码良好,没有造成对象不被垃圾回收的情况,所以说虽然我们不断的操作会不断的生成很多对象,而在虚拟机不断的进行的过程中,这些对象都被回收了,内存占用量会会落到一个稳定的水平;
c) 反之如果代码中存在没有释放对象引用的情况,则的值在每次后不会有明显的回落,随着操作次数的增多的值会越来越大,
直到到达一个上限后导致进程被掉。
d) 此处已进程为例,在我的测试环境中进程所占用的内存的的正常情况下会稳定在之间,而当其值超过后进程就会被。
总之,使用的视图工具可以很方便的确认我们的程序是否存在内存泄漏的可能性。
四、内存分析工具
如果使用确实发现了我们的程序中存在内存泄漏,那又如何定位到具体出现问题的代码片段,最终找到问题所在呢?如果从头到尾的分析代码逻辑,那肯定会把人逼疯,特别是在维护别人写的代码的时候。这里介绍一个极好的内存分析工具 。
MAT是一个插件,同时也有单独的客户端。官方下载地址、介绍和详细的使用教程请参见:,在此不进行说明了。另外在安装后的帮助文档里也有完备的使用教程。在此仅举例说明其使用方法。我自己使用的是的插件,使用插件要比稍微方便一些。
使用进行内存分析需要几个步骤,包括:生成文件、打开并导入文件、使用的视图工具分析内存。以下详细介绍。
(一) 生成.hprof文件
生成文件的方法有很多,而且的不同版本中生成的方式也稍有差别,我使用的版本的是,各个版本中生成文件的方法请参考:
http://android.git.kernel.org/?p=platform/dalvik.a=blob_f=docs/heap-profiling.hb=HEAD。
1. 打开并切换到透视图,同时确认、和视图已经打开了;
2. 将手机设备链接到电脑,并确保使用“调试”模式链接,而不是““模式;
3. 链接成功后在视图中就会看到设备的序列号,和设备中正在运行的部分进程;
4. 点击选中想要分析的应用的进程,在视图上方的一行图标按钮中,同时选中“”和“”两个按钮;
5. 这是工具将会自动生成当前选中进程的文件,并将其进行转换后存放在当中,如果你已经安装了插件,那么此时将会自动被启用,并开始对文件进行分析;
注意:第步和第步能够正常使用前提是我们需要有,并且当前进程有向中写入的权限,否则文件不会被生成,在中会显示诸如
ERROR/dalvikvm(8574): hprof: can't open /sdcard/com.xxx.hprof-hptemp: Permission denied.
如果我们没有,或者当前进程没有向写入的权限(如),那我们可以这样做:
6. 在当前程序中,例如中某些代码中,可以使用中的:
public static void dumpHprofData(String fileName) throws IOException
方法,手动的指定文件的生成位置。例如:
xxxButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
android.os.Debug.dumpHprofData("/data/temp/myapp.hprof");
上述代码意图是希望在被点击的时候开始抓取内存使用信息,并保存在我们指定的位置:,这样就没有权限的限制了,而且也无须用。但要保证目录是存在的。这个路径可以自己定义,当然也可以写成当中的某个路径。
(二) 使用MAT导入.hprof文件
1. 如果是自动生成的文件,可以使用插件直接打开(可能是比较新的才支持);
2. 如果自动生成的文件不能被直接打开,或者是使用方法手动生成的文件,则需要将文件进行转换,转换的方法:
例如我将文件拷贝到上的目录下,并输入命令,其中为原始文件,为转换过后的文件。转换过后的文件自动放在目录下。,到此为止,文件处理完毕,可以用来分析内存泄露情况了。
3. 在中点击,或者打的。在中点击,浏览并导入刚刚转换而得到的文件。
(三) 使用MAT的视图工具分析内存
导入文件以后,会自动解析并生成报告,点击,并按分组,选择自己所定义的类点右键,在弹出菜单中选择。这时会列出所有可疑类,右键点击某一项,并选择,会进一步筛选出跟程序相关的所有有内存泄露的类。据此,可以追踪到代码中的某一个产生泄露的类。
MAT的界面如下图所示。
具体的分析方法在此不做说明了,因为在的官方网站和客户端的帮助文档中有十分详尽的介绍。
了解中各个视图的作用很重要,例如中介绍的。
总之使用分析内存查找内存泄漏的根本思路,就是找到哪个类的对象的引用没有被释放,找到没有被释放的原因,也就可以很容易定位代码中的哪些片段的逻辑有问题了。
至此请各位自己动手,丰衣足食吧!
浏览: 533702 次
来自: 成都
浏览量:13465
浏览量:13874
浏览量:33288
多谢分享~
好文章的。
引用classes.dex.dex2jar.jar
拖入 j ...
讲解的简明易懂,多谢啦!
更为详细的图文介绍,可参考这个http://blog.csdn ...Android下分析内存泄露 - 简书
Android下分析内存泄露
This post is a permitted translation of
and I add some text and screenshots for android studio users.Origin Author: follow badoo on
Translator: Miao1007
本文仅仅是译文,而且比较旧,有建议/想法请到原文提问
截至androidstudio1.5,内部已经(点击查看视频)分析泄漏,或者跑Lint进行静态检查即可,故本文不再更新。
MAT仅仅是工具,不能说“很多引用”就等于“内存泄漏”,具体是否泄漏还要看场景。
Android使用java作为平台开发,帮助了我们解决了很多底层问题,比如内存管理,平台依赖等等。然而,我们也经常遇到OutOfMemoey问题,垃圾回收到底去哪了?
接下来是一个Handler Leak的例子,它一般会在编译器中被警告提示。
所需要的工具
Android Studio 1.1 or higher
Eclipse MemoryAnalyzer
public class NonStaticNestedClassLeakActivity extends ActionBarActivity {
TextView textV
public static final String TAG = NonStaticNestedClassLeakActivity.class.getSimpleName();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_non_static_nested_class_leak);
textView = (TextView)findViewById(R.id.textview);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override public void
textView.setText("Done");
}//a mock for long time work
}, 800000L);
这是一个非常基础的Activity.注意这个匿名的Runnable被送到了Handler中,而且延迟非常的长。现在我们运行这个Activity,反复旋转屏幕,然后导出内存并分析。
导入 Memory 到Eclipse MemoryAnalyzer
使用Androidstudio导出 heap dump
Android Studio dump Memory Analyze
点击左下角的Android
选中你的程序的包名
点击 initiates garbage collection on selected vm
点击 dump java heap for selected client
打开MAT,进行分析
MAT是对java heap中变量分析的一个工具,它可以用于分析内存泄露。
点击OQL图标
在窗口输入select * from instanceof android.app.Activity并按Ctrl + F5或者!按钮
奇迹出现了,现在你发现泄露了许多的activity
这个真是相当的不容乐观,我们来分析一下为什么GC没有回收它
在OQL(Object Query Language)窗口下输入的查询命令可以获得所有在内存中的Activities,这段查询代码是不是非常简单高效呢?
点击一个activity对象,右键选中Path to GC roots
Message in looper hold a reference to Activity
在打开的新窗口中,你可以发现,你的Activity是被this$0所引用的,它实际上是匿名类对当前类的引用。this$0又被callback所引用,接着它又被Message中一串的next所引用,最后到主线程才结束。
任何情况下你在class中创建非静态内部类,内部类会(自动)拥有对当前类的一个强引用。
一旦你把Runnable或者Message发送到Handler中,它就会被放入LooperThread的消息队列,并且被保持引用,直到Message被处理。发送postDelayed这样的消息,你输入延迟多少秒,它就会泄露至少多少秒。而发送没有延迟的消息的话,当队列中的消息过多时,也会照成一个临时的泄露。
尝试使用static inner class来解决
现在把Runnable变成静态的class
StaticClass
现在,摇一摇手机,导出内存
StaticClass_memory_analyze
为什么又出现了泄露呢?我们看一看Activities的引用.
StaticClass_memory_analyze_explained
看到下面的mContext的引用了吗,它被mTextView引用,这样说明,使用静态内部类还远远不够,我们仍然需要修改。
使用弱引用 + static Runnable
现在我们把刚刚内存泄露的罪魁祸首 - TextView改成弱引用。
StaticClassWithWeakRef_code
再次注意我们对TextView保持的是弱引用,现在让它运行,摇晃手机
小心地操作WeakReferences,它们随时可以为空,在使用前要判断是否为空.
StaticClassWithWeakRef_memory_analyze
哇!现在只有一个Activity的实例了,这回终于解决了我们的问题。
所以,我们应该记住:
使用静态内部类
Handler/Runnable的依赖要使用弱引用。
如果你把现在的代码与开始的代码相比,你会发现它们大不相同,开始的代码易懂简介,你甚至可以脑补出运行结果。
而现在的代码更加复杂,有很多的模板代码,当把postDelayed设置为一个短时间,比如50ms的情况下,写这么多代码就有点亏了。其实,还有一个更简单的方法。
onDestroy中手动控制声明周期
Handler可以使用removeCallbacksAndMessages(null),它将移除这个Handler所拥有的Runnable与Message。
//Fixed by manually control lifecycle
@Override protected void onDestroy() {
super.onDestroy();
myHandler.removeCallbacksAndMessages(null);
现在运行,旋转手机,导出内存
removeCallbacks_memory_analyze
Good!只有一个实例。
这样写可以让你的代码更加简洁与可读。唯一要记住的就是就是要记得在生命周期onDestory的时候手动移除所有的消息。
使用WeakHander
(这个是第三方库,我就不翻译了,大家去上去学习吧)
在Handler中使用postDelayed需要额外的注意,为了解决问题,我们有三种方法
使用静态内部Handler/Runnable + 弱引用
在onDestory的时候,手动清除Message
使用Badoo开发的第三方的
这三种你可以任意选用,第二种看起来更加合理,但是需要额外的工作。第三种方法是我最喜欢的,当然你也要注意WeakHandler不能与外部的强引用共同使用。
本博客将长期保持原创性,翻译文章费时费力,如果你认为我的免费劳动有价值的话,不妨帮忙点赞或者关注我吧!
bWlhbzEwMDdAZ21haWwuY29tCg==

我要回帖

更多关于 qq红包扫雷 的文章

 

随机推荐