`
java-mans
  • 浏览: 11440106 次
文章分类
社区版块
存档分类
最新评论

Android内存泄漏简介

 
阅读更多

前言

不少人认为JAVA程序,因为有垃圾回收机制,应该没有内存泄露。

其实如果我们一个程序中,已经不再使用某个对象,但是因为仍然有引用指向它,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成了内存泄露。如果我们的java运行很久,而这种内存泄露不断的发生,最后就没内存可用了。当然java的,内存泄漏和C/C++是不一样的。如果java程序完全结束后,它所有的对象就都不可达了,系统就可以对他们进行垃圾回收,它的内存泄露仅仅限于它本身,而不会影响整个系统的。C/C++的内存泄露就比较糟糕了,它的内存泄露是系统级,即使该C/C++程序退出,它的泄露的内存也无法被系统回收,永远不可用了,除非重启机器。

Android的一个应用程序的内存泄露对别的应用程序影响不大。为了能够使得Android应用程序安全且快速的运行,Android的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运行的Android为不同类型的进程分配了不同的内存使用上限,如果程序在运行过程中出现了内存泄漏的而造成应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill,这使得仅仅自己的进程被kill掉,而不会影响其他进程(如果是system_process等系统进程出问题的话,则会引起系统重启)。

一、引用没释放造成的内存泄露

1.1注册没取消造成的内存泄露

这种Android的内存泄露比纯java的内存泄露还要严重,因为其他一些Android程序可能引用我们的Anroid程序的对象(比如注册机制)。即使我们的Android程序已经结束了,但是别的引用程序仍然还有对我们的Android程序的某个对象的引用,泄露的内存依然不能被垃圾回收。

比如

假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则可以在LockScreen中定义一个PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当需要显示锁屏界面的时候就会创建一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。

但是如果在释放LockScreen对象的时候忘记取消我们之前注册的PhoneStateListener对象,则会导致LockScreen无法被垃圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大量的LockScreen对象没有办法被回收而引起OutOfMemory,使得system_process进程挂掉。

虽然有些系统程序,它本身好像是可以自动取消注册的(当然不及时),但是我们还是应该在我们的程序中明确的取消注册,程序结束时应该把所有的注册都取消掉

1.2集合中对象没清理造成的内存泄露

我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了

二、资源对象没关闭造成的内存泄露

资源性对象比如(CursorFile文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄露。因为有些资源性对象,比如SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null.在我们的程序退出时一定要确保我们的资源性对象已经关闭

程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。

三、一些不良代码成内存压力

有些代码并不造成内存泄露,但是它们,或是对没使用的内存没进行有效及时的释放,或是没有有效的利用已有的对象而是频繁的申请新内存,对内存的回收和分配造成很大影响的,容易迫使虚拟机不得不给该应用进程分配更多的内存,造成不必要的内存开支。

3.1、Bitmap没调用recycle()

Bitmap对象在不使用时,我们应该先调用recycle(),然后才它设置为null.

虽然Bitmap在被回收时可以通过BitmapFinalizer来回收内存。但是recycle()可以立即释放Native内存

注意这里其实是释放的Native内存。

可以通过dumpsys meminfo命令查看一个进程的内存情况。

示例:adb shell "dumpsys meminfo com.lenovo.robin"

运行结果。

Applications Memory Usage (kB):

Uptime: 18696550 Realtime: 18696541


** MEMINFO in pid 7985 [com.lenovo.robin] **

native dalvik other total

size: 4828 5379 N/A 10207

allocated: 4073 2852 N/A 6925

free: 10 2527 N/A 2537

(Pss): 608 317 1603 2528

(shared dirty): 2240 1896 6056 10192

(priv dirty): 548 36 1276 1860


Objects

Views: 0 ViewRoots: 0

AppContexts: 0 Activities: 0

Assets: 2 AssetManagers: 2

Local Binders: 5 Proxy Binders: 11

Death Recipients: 1

OpenSSL Sockets: 0


SQL

heap: 0 MEMORY_USED: 0

PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0

关于内存统计的更多内容请参考《Android内存泄露利器(内存统计篇)

3.2、构造Adapter时,没有使用缓存的convertView

以构造ListView的BaseAdapter为例,在BaseAdapter中提共了方法:

publicViewgetView(intposition,ViewconvertView,ViewGroupparent)

来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的listitem的view对象会被回收,然后被用来构造新出现的最下面的listitem。这个构造过程就是由getView()方法完成的,getView()的第二个形参ViewconvertView就是被缓存起来的listitem的view对象(初始化时缓存中没有view对象则convertView是null)。

由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费时间,也造成内存垃圾,给垃圾回收增加压力,如果垃圾回收来不及的话,虚拟机将不得不给该应用进程分配更多的内存,造成不必要的内存开支。ListView回收listitem的view对象的过程可以查看:

android.widget.AbsListView.java-->voidaddScrapView(Viewscrap)方法。

示例代码

publicViewgetView(intposition,ViewconvertView,ViewGroupparent){

Viewview=newXxx(...);

......

returnview;

}

修正示例代码

publicViewgetView(intposition,ViewconvertView,ViewGroupparent){

Viewview=null;

if(convertView!=null){

view=convertView;

populate(view,getItem(position));

...

}else{

view=newXxx(...);

...

}

returnview;

}

<wbr><strong>3.3、ThreadLocal使用不当</strong> <div>如果我们粗暴的把ThreadLocal设置null,而不调用<span style="color:#ff00ff">remove()</span>方法或set(null),那么就可能造成ThreadLocal绑定的对象长期也能被回收,因而产出内存泄露。</div> <div>关于此的更多内容请参考《<a title="阅读全文" target="_blank" href="http://hubingforever.blog.163.com/blog/static/1710405792011102411334093/">ThreadLocal的内存泄露</a>》</div> </wbr>
3.4、WebView对象没有销毁
当我们不要使用WebView对象时,应该调用它的destory()函数来销毁它,并释放其占用的内存,否则其占用的内存长期也不能被回收,从而造成内存泄露。

四、JNI代码的内存泄露
关于此的详细内容请参考《JNI引用与垃圾回收
分享到:
评论

相关推荐

    android内存泄露简介

    讲解关于android内存泄露的各种情况

    Android webview 内存泄露的解决方法

    Android webview 内存泄露的解决方法 最近在activity嵌套webview显示大量图文发现APP内存一直在涨,没法释放内存,查了很多资料,大概是webview的一个BUG,引用了activity导致内存泄漏,所以就尝试传递...

    Android处理内存泄漏的代码例子

    Android处理内存泄漏的代码例子。用于演示避免内存泄漏的几种方法,包括:关闭游标、重用适配、回收图像、注销监听、释放引用。

    Android 内存泄露原因分析

    Android 内存泄露原因分析。通过原因分析,再接合代码可查明具体原因,发现对策

    Android 内存泄露 Mat工具分析

    Android 内存泄露 Mat工具分析。非常好的分析工具讲解

    android内存泄露测试

    android 内存泄露测试.

    Android Native 内存泄漏系统化解决方案

    主要介绍了Android Native 内存泄漏系统化解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    Android内存泄漏调试教程

    Android内存泄漏调试教程,Android内存泄漏调试教程,Android内存泄漏调试教程

    android内存泄露的检测和排查

    android内存泄露的检测和排查,已经附带一个锁屏内存泄露的例子分析。

    android检查内存泄露

    android检查内存泄露和用法 &lt;!--==============================================================================--&gt; android:name="com.squareup.leakcanary.internal.HeapAnalyzerService" android:enabled...

    android系统分析内存泄露测试

    android系统分析内存泄露测试android系统分析内存泄露测试android系统分析内存泄露测试

    Android内存OOM优化详解.pdf

    Android 内存 OOM 优化和治理,Android 内存泄漏原因详解与应对措施,Android 中的 Bitmap 使用详解,Android 中的 Bitmap 内存治理和优化详解,Android 内存分析命令详解,Java内存模型。Android 内存 OOM 优化和...

    android 内存泄露 分析方法

    android 内存泄露 分析方法.非常难对应的问题。首先弄明白原理

    使用Android Studio检测内存泄露(LeakCanary)

    本篇文章主要介绍了用Android Studio检测内存泄露的问题的解决方法,Android Studio在为我们提供了良好的编码体验的同时,也提供了许多对App性能分析的工具,下面我们一起来了解一下。

    androidStudio内存泄漏分析

    用AndroidStudio内存泄漏分析,亲测可用,在项目中充分验证。

    Android 内存泄漏

    自己收集的android方面关于内存泄漏方面的视频以及学习资料,自己之前花钱搞到的,现在对外公开。文档里面是链接和密码,永久有效!

    android内存泄露:4、Toast的错误使用导致内存泄露

    详细可参考博文:原创 android内存泄露:3、Handler的错误使用导致内存泄露 ,这篇文章我们将介绍:Toast的错误使用导致内存泄露 二、Toast的错误使用导致内存泄露 我们通常,连续点击按钮多次提示的 Toast,它...

    Android 内存泄漏调试经验分享

    二、Android(Java)中常见的容易引起内存泄漏的不良代码 1 (一) 查询数据库没有关闭游标 2 (二) 构造Adapter时,没有使用缓存的 convertView 3 (三) Bitmap对象不在使用时调用recycle()释放内存 4 (四) 释放对象的...

    android 内存泄漏 摘抄

    android 的内存泄漏 和anr的处理情况,挺不错的资源

Global site tag (gtag.js) - Google Analytics