关闭

初识android内存的一些解决方案

标签: 优化app内存内存泄露解决方案
313人阅读 评论(0) 收藏 举报
分类:

资源地址:

http://www.csdn.net/article/2015-09-18/2825737/4

http://blog.csdn.net/autism_mimi/article/details/50427197 


害羞笔者开发也有几年了,遇到困扰最大的也莫过于android内存优化与管理的问题最令人头疼。记得刚开始实习那会写app,写出的东西经常被上司批,然后又噼里啪啦的改...

我想作为一个coder应该经历这些事是很头大的.但是有什么办法呢,毕竟你只是一个coder,所以你得努力的提升自己才行....笔者最近准备换工作面了几家都说要什么github,CSDN之类的文章,瞬间笔者就忧郁了 。平时都是把笔记什么的都整理在为知笔记里面....想想也是苦逼。最近出来发几篇虽有点磨刀的感觉,但我个人觉得还是对我提高还是有一定的好处的,我想这里交流技术也挺好。有不足希望大家指出···

对于内存这块,我其实也只能说说自己的一些见解。

内存泄露是指程序在运行过程中动态申请的内存空间不再使用后没有及时释放,从而很可能导致应用程序内存无线增长。更广义的内存泄露包括未对系统的资源的及时释放,比如Bitmap等。其实Android 系统中本身没有为内存提供交换区,它是使用paging与memory-mapping的机制来管理内存。

1.1,Bitmap对象内存占用

我不知道大家有木有遇到这种情况,反正我是见多了。每次接手别人代码<尤其是初创型的基本都是这样>,我们大家都是知道的现在我们有很多的开源库如:ImageLoader,Glide,Picasso,Afinal之类的很多很多,我相信大家也都用的轻车熟路,但是为什么我们的内存还是蹭蹭的往上涨呢 ? 

个人见解有以下的几个原因: 

1,用了第三方库之后没有及时的把内存释放掉,就拿ImageLoader来讲我们只是一味的disPlayImage可是我们并没有clear 

2,本地资源图片资源图片我们一般直接在XML文件中<ImageView />标签来设置什么Src ,backGround之类的,往往加载一个以M结尾的图。。大家都是知道的我们的layout文件最终是映射成对象存储在我们内存中。那么这些谁会来处理呢?日积月累,你不崩,我吃屎三斤-。- 

3,大家应该用过glide或者picasso,这两个我想不陌生,我记得当时也看过一个帖子关于这两个的对比后来自己做了一个小实验,确实如此。同样加载一样的图片只是将图片解码设置ARGB_8888/RBG_565内存几乎是倍增不止。所以建议大家还是把这些细节做好。

建议:

  .inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入。

  .decode format:解码格式,选择ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差异。

.clear :及时利用第三方库中包装的方法将bitmap释放。

2,复用

2.1 对象复用这个概念其实我也是参考了凯哥当时的一篇博文


对于这个概念,我觉得是比较好的一种处理方式,我不知道大家有没有研究过单例模式,其实在这个模式中也是有体现这个概念的,其中的容器单例模式可以用于对象池这个概念。其实大家读过android源码的肯定知道,其实内部的context对象,layoutInfalter也就是利用pool这个概念。不过大家慎用,这个pool概念并不是将所有的对象都存入容器,而一般我们只是将全局通用对象存入便于存取。

2.2资源复用

Android系统本身内置了很多的资源,比如字符串、颜色、图片、动画、样式以及简单布局等,这些资源都可以在应用程序中直接引用。这样做不仅能减少应用程序的自身负重,减小APK的大小,还可以在一定程度上减少内存的开销,复用性更好。但是也有必要留意Android系统的版本差异性,对那些不同系统版本上表现存在很大差异、不符合需求的情况,还是需要应用程序自身内置进去。

Android虚拟机的垃圾回收采用的是根搜索算法。GC会从根节点(GC Roots)开始对heap进行遍历。到最后,部分没有直接或者间接引用到GC Roots的就是需要回收的垃圾,会被GC回收掉。而内存泄漏出现的原因就是存在了无效的引用,导致本来需要被GC的对象没有被回收掉

通常来说,Activity的泄漏是内存泄漏里面最严重的问题,它占用的内存多,影响面广,我们需要特别注意以下两种情况导致的Activity泄漏:

  • 内部类引用导致Activity的泄漏

最典型的场景是Handler导致的Activity泄漏,如果Handler中有延迟的任务或者是等待执行的任务队列过长,都有可能因为Handler继续执行而导致Activity发生泄漏。此时的引用关系链是Looper -> MessageQueue -> Message -> Handler -> Activity。为了解决这个问题,可以在UI退出之前,执行remove Handler消息队列中的消息与runnable对象。或者是使用Static + WeakReference的方式来达到断开Handler与Activity之间存在引用关系的目的。

  • Activity Context被传递到其他实例中,这可能导致自身被引用而发生泄漏。
  • 对于Activity的泄露在代码中我们确实是最常见到的单例是最常见的例子
  • public class ResponseManager<T> {
        public static ResponseManager mResponse;
    
        /**
         * 单例获取Resonse对象
         *
         * @return
         */
        public static ResponseManager getInstance(Context context) {
            synchronized (ResponseManager.class) {
                if (null == mResponse) {
                    mResponse = new ResponseManager(context);
                }
            }
            return mResponse;
        }}
    
    大家可以看到这个context如果我们在act中调用就是activity对象,那么就会造成泄露。
  • 所以在这种情况下我们更希望传入的是getapplication。
  • 建议 :
  • 内部类引起的泄漏不仅仅会发生在Activity上,其他任何内部类出现的地方,都需要特别留意!我们可以考虑尽量使用static类型的内部类,同时使用WeakReference的机制来避免因为互相引用而出现的泄露。
  • 监听器广播的注销,Cursor对象是否及时关闭等等之类我想这都是代码规范,大家应该都了解。


  • 那么现在介绍大家在as开发中经常会利用的工具 :首先LeakCanary这玩意我想大家都是烂熟于心了<如果大家有什么疑问可以点击打开链接>,其次就是eclipse中mat,这里主要介绍下androidstudio中的内存检测。自带AndroidMonitor.
  • 首先打开Android Studio,编译代码,在模拟器或者真机上运行App,然后点击[Anroid monitor],在Android Monitor下点击Monitor对应的Tab,进入如下界面:
  • 在Memory一栏中,可以观察不同时间App内存的动态使用情况,点击可以手动触发GC,点击可以进入HPROF Viewer界面,查看Java的Heap,如下图

然后在右边的找出你所泄露的act,再在对应得tree下进行定位分析这样就可以准确的找到你的内存泄漏位置点在哪里了,一般情况act泄露比较多。

Reference Tree代表指向该实例的引用,可以从这里面查看内存泄漏的原因,Shallow Size指的是该对象本身占用内存的大小,Retained Size代表该对象被释放后,垃圾回收器能回收的内存总和。


finally下,以上只是我的小小的总结,很多细节性的东西都是直接忽略掉了。如果大家有兴趣可以依照我上面的链接多去了解下 。如果大家有更好的建议,或者文中有什么不当的处理希望提出来共同进步。谢谢~~


1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1566次
    • 积分:40
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档