记一次内存泄露排查

最后在实现一个无限循环的ViewPager,展示图片,功能实现了,但是运行一段时间之后会挂掉。

多亏了AndroidStudio的Memory Monitor,发现了内存一直在增长。

怎么触发gc内存都不会减少,确定了内存泄露了,但是不知哪里出问题了。

一时想到的排查内存泄露的工具,就是MAT了,但是没找到AndroidStudio的MAT插件。

只能先把java heap dump出来先,如下图所示

dump出来之后,hprof文件会保存在项目下captures目录,之前一直不知到,找了很久。。。

如果切换到Captures这个tab,是可以直接看到HeapSnapshot的,如下图所示

但是这个hprof文件mat不认,需要转换一下,点击hprof文件右键,转成标准.hprof文件即可

然后到eclipse用mat插件打开,如果没有安装mat插件请自行搜索解决

window->open perspective->memory analysis

在memory analysis界面下

File->Open Heap Dump->选中上面Android Studio转换之后的.hprof文件即可

在OverView下面点击Top Consumers, 如下图。byte占了大头,内存基本都给它用了

byte占用这么多内存,一想到的就是bitmap没被释放了。

回去研究我的代码

PagerAdapter代码如下

 1 public class SlidePicPagerAdapter extends PagerAdapter {
 2
 3     private List<SlidePicModel> mItems;
 4     private int itemSize;
 5
 6     public void setItems(List<SlidePicModel> items) {
 7         mItems = items;
 8         itemSize = items.size();
 9     }
10
11     @Override
12     public int getCount() {
13         return ListUtils.isEmpty(mItems) ? 0 : Integer.MAX_VALUE;
14     }
15
16     @Override
17     public boolean isViewFromObject(View view, Object object) {
18         return view == object;
19     }
20
21     @Override
22     public Object instantiateItem(ViewGroup container, int position) {
23         Context context = container.getContext();
24         SlidePicModel item = mItems.get(getCurPos(position));
25         ImageView iv = item.getImageView();
26         if(iv == null){
27             iv = new ImageView(context);
28             item.setImageView(iv);
29         }
30         final String imgUrl = ImageUrlExtends.getImageUrl(item.getUrl());
31         Picasso.with(context).load(imgUrl).into(iv);
32         container.addView(iv);
33         return iv;
34     }
35
36     @Override
37     public void destroyItem(ViewGroup container, int position, Object object) {
38         View imageView = (View) object;
39         container.removeView(imageView);
40     }
41
42
43     private int getCurPos(int pos){
44         return pos % mItems.size();
45     }
46 }

我用的是Picasso去加载图片。首先把picasso加载图片给屏蔽了,发现内存正常了,擦,以为我发现了个bug,先去给Picasso提Bug去呢。

再看看我代码,第28行,我把ImageView给缓存到数据源SlidePicModel的成员变量里了。

SlidePicModel代码如下

 1 public class SlidePicModel {
 2
 3     private ImageView imageView;
 4     private String url;
 5
 6     public SlidePicModel(String url) {
 7         this.url = url;
 8     }
 9
10     public ImageView getImageView() {
11         return imageView;
12     }
13
14     public void setImageView(ImageView imageView) {
15         this.imageView = imageView;
16     }
17
18     public String getUrl() {
19         return url;
20     }
21
22     public void setUrl(String url) {
23         this.url = url;
24     }
25 }

要想想,我这个数据源mItems里面代表好几百张图片,而我的应用是无限循环显示图片,也即是我的数据库mItems是不会回收的。

本来显示完图片,ImageView是要被回收的,但是,却被我数据源里面的model引用着,几百张图片的bitmap被引用着,不能回收,app肯定内存溢出。

解决方法如下,把ImageView这个成员变量设置成弱引用,当内存不足时,ImageView可以被内存回收。问题解决,代码如下

 1 public class SlidePicModel {
 2
 3
 4     private String url;
 5     private WeakReference<ImageView> mImageViewRef;
 6     public SlidePicModel(String url) {
 7         this.url = url;
 8     }
 9
10     public ImageView getImageView() {
11         return mImageViewRef == null ? null : mImageViewRef.get();
12     }
13
14     public void setImageView(ImageView imageView) {
15 //        this.imageView = imageView;
16         mImageViewRef = new WeakReference<ImageView>(imageView);
17     }
18
19     public String getUrl() {
20         return url;
21     }
22
23     public void setUrl(String url) {
24         this.url = url;
25     }
26 }

当然了,更好的办法就是,这个ImageView成员变量完全没有存在的必要,但是当时一时把代码写错,出刚好让我研究了一下内存泄露,对内存泄露有更深的认识。

总结:

之前就有看到一些文章在建议,不要把Activity当成静态成员变量。

其实从我上面出现的问题里就可以发现一样的道理。上面是因为数据源一直存在,没有被内存回收,所以引用的ImageView也没有被回收,导致内存溢出。

同理,如果把Activity当成静态成员变量。那么它的生命周期就会和app的生命周期一样,Activity里所引用的对象都不会被释放,即使activity已经结束了,这就会导致内存举出。

使用context的时候,能使用ApplicationContext就使用AplicationContext,如果把Activity当成context传给别人,要注意内存泄露,具体看我另一篇博客

这里还说明另外一个问题,就是变量,能不用成员变量就尽量不要用,不然,一旦内存泄露,会把成员变量的内存也泄露了,我这里就是成员变量导致的内存泄露

时间: 2024-08-02 11:49:44

记一次内存泄露排查的相关文章

记一次内存泄露优化过程

背景 项目目前存在使用久了或者重复打开关闭某个页面,内存会一直飙升,居高不下,频繁发生GC.静置一段时间后,情况有所改善,但是问题依旧明显,如图1-1.1-2. 图1-1.操作时的内存使用情况 图1-2.静置时的内存使用情况 如上图1-1,是通过Android Studio查看内存(灰色)和CPU(红色)使用情况,可以看出内存有发生抖动并且是处于比较高的状态,再者,从logcat可以看到一直发生GC,如下图1-3: 图1-3. 出现这些情况,是有很多因素造成的,最主要的原因是发生了内存泄露:页面

记一次内存泄露调试(memory leak)-Driver Monkey

Author:DriverMonkey Mail:[email protected] Phone:13410905075 QQ:196568501 硬件环境:AM335X 软件环境:linux 3.2 现象:1)系统运行一晚上,配置硬件操作失效 2)系统放置在那,没有用户输入会自己死机 调试过程: 第一步:分析硬件配置失效原因,怀疑配置硬件代码有问题 最后发现 代码 调用 system() 函数配置硬件没有调用成功 返回值 为 -1. 第二步: 继续上一步 分析 system() 在什么情况下会

pomelo内存泄露排查方法

工具: node-inspector pomelo-cli chrome 步骤 通过pomelo-cli中的dump memory,导出当前服务器的内存堆栈文件:dump1.heapsnapshot. 服务器运行指定模块一段时间后,导出堆栈文件:dump2.heapsnapshot. 用chrome 读取堆栈文件:打开开发者工具->Profiles->Load->选择堆栈文件.先load 前面的dump1,再Load dump2. 在Profiles的左侧会有份文件列表,重点看两份的差异

Android 源码系列之&lt;十三&gt;从源码的角度深入理解LeakCanary的内存泄露检测机制(中)

转载请注明出处:http://blog.csdn.net/llew2011/article/details/52958563 在上篇文章Android 源码系列之<十二>从源码的角度深入理解LeakCanary的内存泄露检测机制(上)中主要介绍了Java内存分配相关的知识以及在Android开发中可能遇见的各种内存泄露情况并给出了相对应的解决方案,如果你还没有看过上篇文章,建议点击这里阅读一下,这篇文章我将要向大家介绍如何在我们的应用中使用square开源的LeakCanary库来检测应用中出

内存泄露从入门到精通三部曲之排查方法篇

内存泄露从入门到精通三部曲之排查方法篇 最原始的内存泄露测试 重复多次操作关键的可疑的路径,从内存监控工具中观察内存曲线,是否存在不断上升的趋势且不会在程序返回时明显回落.这种方式可以发现最基本,也是最明显的内存泄露问题,对用户价值最大,操作难度小,性价比极高. MAT内存分析工具 2.1 MAT分析heap的总内存占用大小来初步判断是否存在泄露 在Devices 中,点击要监控的程序. 点击Devices视图界面中最上方一排图标中的“Update Heap” 点击Heap视图 点击Heap视图

hadoop1.0 TaskTracker因为分布式缓存导致内存泄露的一次问题排查

上周五同事到公司说凌晨的时候有值班同事打电话给他,有部分job卡住了,运行了很长时间都没运行完成,由于是凌晨,他没来得及详细的查看日志,简单的把有问题的tasktracker重启了一下,只有一个节点的TaskTracker进程停掉,让我查一下具体是什么问题.以下是排查过程: 1.登陆到停掉TT进程的处理机 (1).查看磁盘空间 磁盘没有出现空间不足的情况. (2).top查看负载和内存使用情况: 根据上图看出内存和负载都不算高,也不存在僵尸进程. 2.查看进程日志 1.log4j日志: 2014

关于排查python内存泄露的简单总结

这次的内存泄露问题是发生在多线程场景下的. 各种工具都试过了,gc,objgraph, pdb,pympler等,仍然没有找到问题所在. pdb感觉用起来很方便,可以调试代码,对原来的代码无侵入性. 排查问题的过程中,多线程场景下,相关的工具,显得无力的. 使用objgraph时,代码执行很长时间后,show_growth()显示没有新创建的对象.这个可能是因为objgraph只针对当前线程的上下文. pympler,也是同样的问题. 最后,是通过分析进程的资源占用数据,找到的问题位置. 总结一

记一次调试python内存泄露的问题

转载:http://www.jianshu.com/p/2d06a1a01cc3 这两天由于公司需要, 自己编写了一个用于接收dicom文件(医学图像文件)的server. 经过各种coding-debuging-coding-debuging之后, 终于上线了, 上线后心里美滋滋的, 一切正常. 第二天一上班, 负责人和我说接收太慢了, 卡的要死. 我想难道是python本身的问题?(程序员本征思维)我好奇的打开了终端输入 ps -aux | grep python 找到进程id 即 2161

android 内存泄露调试

一.概述 1 二.Android(Java)中常见的容易引起内存泄漏的不良代码 1 (一) 查询数据库没有关闭游标 2 (二) 构造Adapter时,没有使用缓存的 convertView 3 (三) Bitmap对象不在使用时调用recycle()释放内存 4 (四) 释放对象的引用 4 (五) 其他 5 三.内存监测工具 DDMS --> Heap 5 四.内存分析工具 MAT(Memory Analyzer Tool) 7 (一) 生成.hprof文件 7 (二) 使用MAT导入.hpro