内存泄漏简单介绍

java能够保证当没有引用指向对象的时候,对象会被垃圾回收器回收。与c语言自己申请的内存自己释放相比,java程序猿轻松了非常多。可是并不代表java程序猿不用操心内存泄漏。当java程序发生内存泄漏的时候往往具有隐蔽性。因此要借助一些专业的平台资源去保证安全性,比如能够通过加密实现

定义

引用百度百科的定义:“用动态存储分配函数动态开辟的空间,在使用完成后未释放,结果导致一直占领该内存单元。

直到程序结束”。从程序员的角度来看“内存泄漏”,事实上就是一个对象的生命周期超出了程序员所预期的长度(就叫它“该死不死”吧!

),那么这个对象就泄漏了。

android开发中的内存泄漏

android应用程序本身系统分配的内存非常少,一旦发生泄漏,程序非常快就会变得非常卡顿,直至OOM崩溃。接下来将通过一个案例(仅仅是为了分析内存泄漏而设计的玩具程序。切勿模仿)来介绍内存泄漏分析工具MAT。以及内存分析的技巧。

公欲善其事。先利其器

准备内存泄漏的分析工具,能够安装eclipse插件mat。假设eclise安装mat不成功,那可能是缺少必要的libs。假设嫌找库麻烦,能够仅仅勾选第二项安装,只是会缺少某些功能,可是也够用了。 

在线安装:http://download.eclipse.org/mat/1.4/update-site/ 

下载安装:http://mirror.hust.edu.cn/eclipse//mat/1.4/MemoryAnalyzer-1.4.0.201406041413.zip

mat插件怎样使用

假设已经安装成功好了mat工具,使用起来很easy,首先将须要分析的应用程序跑起来,打开eclipse的devices视图你将会看到点击“Dump Hprof file”button,注意点击一下就能够了,然后等待(等待几秒)dump一个内存快照出来,接下来就会自己主动打开mat的视图了,假设mat没有安装成功,会让你保存一个.hprof文件到本地。

看看以下的图例吧

dump hprof启动mat工具

人为制造一个内存泄漏

自己定义一个ActivityManager。提供两个方法,分别用来注冊与反注冊Activity。

shareid=3987145482&uk=2131650961" title="源代码下载" target="_blank" style="margin:0px; padding:0px; border:0px; vertical-align:baseline; outline:none">源代码下载

public class ActivityManager {
private List<Activity> mActivities = new ArrayList<>();
private static ActivityManager sInstance; private ActivityManager() {
}; public static ActivityManager instance() {
if (sInstance == null) {
sInstance = new ActivityManager();
} return sInstance;
} public void registActivity(Activity activity) {
mActivities.add(activity);
} public void unRigistActivity(Activity activity) {
mActivities.remove(activity);
}
}

在MainActivity的onCreate与onDestroy中分别调用registActivity和registActivity方法进行注冊与反注冊。可是OtherActivity却仅仅是注冊了。而忘记了反注冊。

public class MainActivity extends Activity {
public static final String TAG = MainActivity.class.getSimpleName(); private Button mBtn; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtn = (Button) findViewById(R.id.btn);
mBtn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, OtherActivity.class);
startActivity(intent);
}
}); ActivityManager.instance().registActivity(this);
} @Override
protected void onDestroy() {
super.onDestroy(); ActivityManager.instance().registActivity(this);
} public class OtherActivity extends Activity {
public static final String TAG = OtherActivity.class.getSimpleName(); private Object[] mObjs = new Object[10000];//模拟高速消耗内存。使效果明显
private Button mBtn; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
mBtn = (Button) findViewById(R.id.btn);
mBtn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
for (int i = 0; i < mObjs.length; i++) {
mObjs[i] = new Object();
} finish();
}
}); ActivityManager.instance().registActivity(this);
} @Override
protected void onDestroy() {
super.onDestroy();
}
}

案例中的内存泄漏是人为构造的。所以我们事先已经知道有泄漏了,可是实际的开发过程中。内存泄漏是隐蔽的,一開始我们并不知道,所以我们须要通过一些手段来測试APP是否有内存泄漏。首先在Devices视图中选中须要測试的进程。然后点击Device视图面板的Update Heapbutton。然后打开Heap视图,点击Cause GC。然后重复的在MainActivyt和OtherActivity之间切换。观察Heap size的变化。你会发现内存一直在添加。没有稳定下来的趋势。

这个时候你就有理由怀疑内存泄漏了。

Update heap观察heap size等变化情况

找出泄漏的对象

依照前面mat的使用步骤,dump一个内存快照出来。然后从分析报告中点击“Leak suspects”这里会列车可能泄漏的对象,当中你会发现“ com.vjson.leaks.OtherActivity”的身影。OtherActivity这个类有33个实例。作为代码的生产者,你应该一下子就会发现,原来是OtherActivity泄漏了。

发现它泄漏之后,怎样找出是哪一个对象持有了OtherActivity对象的引用呢?

可能泄漏的报告

找出引用链

使用OQL对象查询语言查询出泄漏的对象,写过SQL的同学一定对她有一种既陌生又熟悉的感觉。和SQL很相似,语法简单易懂,可是很强大select *from com.vjson.leaks.OtherActivity赛选出OtherActivity这一类对象,然后选择“exclude
weak/soft references”赛选出除了软引用和弱引用之外的对象,也就是强引用了!。对象的引用类型不在本文的解说范围,可是你一定要知道“强引用”,“软引用”。“弱引用”。“幽灵引用”,假设不知道自行脑补去吧!

OQL对象查询找出引用链

对象引用链

然后找出GC的根节点,从图二种能够看出,原来Activity对象被ActivityManager里面的ArrayList给hold住了,所以接下来的工作就是在OtherActivity的onDestroy中反注冊,内存泄漏就被攻克了。

Android开发中常见的内存泄漏

对象没有反注冊

数据库cursor没有关闭

Bitmap没有回收

ListView item没有复用

Handler在Activity中定义为非static的匿名内部类

总结

假设耐心的看完本文。那么恭喜你妈妈再也不用操心内存泄漏了。事实上仅仅要掌握了分析问题的技巧与工具,内存泄漏so easy。文章中仅仅是简单的介绍了工具与技巧。这当中还有非常多技巧须要自己去摸索。

Android内存泄漏分析实战的更多相关文章

  1. Android 内存泄漏分析与解决方法

    在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...

  2. Android内存泄漏分析及调试

    尊重原创作者,转载请注明出处: http://blog.csdn.net/gemmem/article/details/13017999 此文承接我的另一篇文章:Android进程的内存管理分析 首先 ...

  3. (转)Android内存泄漏分析及调试

      http://blog.csdn.net/gemmem/article/details/13017999 此文承接我的另一篇文章:Android进程的内存管理分析  首先了解一下dalvik的Ga ...

  4. Android内存泄漏分析

    周末去上海参加了安卓巴士组织的技术论坛,去了才发现自己基础很渣..... 其中提到了android的内存泄漏的问题,回来马上度娘(虽说度娘很渣),整理如下: 一.单例造成的内存泄漏 因为单例的静态特性 ...

  5. android 内存泄漏分析技巧

    java虚拟机执行一般都有一个内存界限,超过这个界限,就会报outofmemory.这个时候一般都是存在内存泄漏.解决内存泄漏问题,窃以为分为两个步骤:分析应用程序是否真的有内存泄漏,找到内存泄漏的地 ...

  6. Android 内存泄漏分析利器——leakcanary

    LeakCanary Android 和 Java 内存泄露检测. “A small leak will sink a great ship.” - Benjamin Franklin 千里之堤, 毁 ...

  7. Android 内存管理分析(四)

    尊重原创作者,转载请注明出处: http://blog.csdn.net/gemmem/article/details/8920039 最近在网上看了不少Android内存管理方面的博文,但是文章大多 ...

  8. Android内存泄漏的检测流程、捕捉以及分析

    https://blog.csdn.net/qq_20280683/article/details/77964208 Android内存泄漏的检测流程.捕捉以及分析 简述: 一个APP的性能,重度关乎 ...

  9. Android内存泄漏原因

    这段时间调试APP的时候,发现程序在加载了过多的bitmap后会崩溃.查看了日志,原来是发生了内存溢出(OOM).第一次遇到这样的问题,那就慢慢排查吧. 内存优化可以参考胡凯大神的博客Android内 ...

随机推荐

  1. 【BZOJ 1018】线段树 **

    1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 3242  Solved: 1084[Submi ...

  2. 【BZOJ 1062】 1062: [NOI2008]糖果雨 (二维树状数组)**

    1062: [NOI2008]糖果雨 Description 有一个美丽的童话:在天空的尽头有一个" 糖果国" ,这里大到摩天大厦,小到小花小草都是用糖果建造而成的.更加神奇的是, ...

  3. BZOJ 4566 JZYZOJ 1547 [haoi2016T5]找相同子串 后缀数组 并查集

    http://172.20.6.3/Problem_Show.asp?id=1547 http://www.lydsy.com/JudgeOnline/problem.php?id=4566 单纯后缀 ...

  4. 初涉springboot(二)

    概述 1.环境说明 2.HelloWorld项目细节   3.小结 一. 关于环境补充 在上一篇的HellWorld项目中,我们构建SpringBoot项目,采用的是jdk1.8版本,springbo ...

  5. 内功心法 -- java.util.LinkedList<E> (1)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------下文主要对java.util ...

  6. sklearn中的超参数调节

    进行参数的选择是一个重要的步骤.在机器学习当中需要我们手动输入的参数叫做超参数,其余的参数需要依靠数据来进行训练,不需要我们手动设定.进行超参数选择的过程叫做调参. 进行调参应该有一下准备条件: 一个 ...

  7. HP-unix如何生成动态库?

    HP-unix系统生成动态库编译的方法? 创建PIC中间文件的编译器选项是+z,创建动态库的链接器标志是-b. 1. cc +z d1.c d2.c /* 编译以".o"为扩展名的 ...

  8. TSearch & TFileSearch Version 2.2 -Boyer-Moore-Horspool search algorithm

    unit Searches; (*-----------------------------------------------------------------------------* | Co ...

  9. Spring JdbcTemplate batchUpdate() 实例

    在某些情况下,可能需要将一批记录插入到数据库中.如果你对每条记录调用一个插件的方法,SQL语句将被重复编译,造成系统缓慢进行. 在上述情况下,你可以使用 JdbcTemplate BATCHUPDAT ...

  10. Java:泛型在编译时会被檫除,Eclipse 如何给出智能提示?

    背景 Java 的泛型是一种语法糖,编译时会被“檫除”,参考文章:http://docs.oracle.com/javase/tutorial/java/generics/,如果没有源代码,Eclip ...