Android内存性能优化(内部资料总结) eoe转载

刚入门的童鞋肯能都会有一个疑问,Java不是有虚拟机了么,内存会自动化管理,我们就不必要手动的释放资源了,反正系统会给我们完成。其实Java中没有指针的概念,但是指针的使用方式依然存在,一味的依赖系统的gc,很容易就造成了内存的浪费。

Java基于垃圾回收的内存机制

Java的内存管理机制会自动回收无用对象所占用的内存,减轻手工管理内存的负担

1、C/C++: 从申请、使用、释放都需要手工管理

2、Java:无用的对象的内存会被自动回收

什么样的对象是无用的对象

1、Java通过引用来操作一个具体的对象,引用类似于C 中的指针。一个对象可以持有其他对象的引用。

2、从一组根对象(GC Roots)开始,按对象之前的引用关系遍历所有对象,在遍历过程中标记所有的可达对象。如果一个对象由根对象出发不可达,则将它作为垃圾收集。

GCRoot 都有哪些?

1、  Class:由系统的类加载器加载的类对象

2、  Static Fields

3、  Thread:活着的线程

4、  Stack Local: java方法的局部变量或参数

5、  JNI Local: JNI方法中的局部引用

6、  JNI Global: 全局的JNI引用

7、  Monitor used: 用于同步的监控对象

8、Help by VM: 用于JVM特殊目的由GC保留的对象

Java程序中的内存泄漏

对象的内存在分配之后无法通过程序的执行逻辑释放对该对象的引用,不能被回收该对象所占内存

内存泄漏的危害

1、  引起OutOfMemoryError

2、  内存占用高时JVM虚拟机会频繁触发GC, 影响程序响应速度

3、内存占用大的程序容易被各种清理优化程序中止,用户也更倾向于卸载这些程序

Android应用的开发语言为Java,每个应用最大可使用的堆内存受到Android系统的限制

Android每一个应用的堆内存大小有限

1、  通常的情况为16M-48M

2、  通过ActivityManager的getMemoryClass()来查询可用堆内存限制

3、3.0(HoneyComb)以上的版本可以通过largeHeap=“true”来申请更多的堆内存

Nexus S(4.2.1):normal 192, largeHeap 512

4、如果试图申请的内存大于当前余下的堆内存就会引发OutOfMemoryError()

5、应用程序由于各方面的限制,需要注意减少内存占用,避免出现内存泄漏。

用MAT工具来检测内存泄漏

在试图窗口中新建一个Memory Analysis会出现一个

没有的可以去http://www.eclipse.org/mat/downloads.php安装一下MAT

在Android 的调试环境DDMS下,找到Heap dump

Dump下当前内存中的镜像文件,*****.hprof

能清楚的看到每一个部分暂用的内存大小。

也可以切换试图,group查看不同包不同类的占用细节。

Heap dump

•       包含了触发Heap dump生成的时刻Java进程的内存快照,主要内容为各个Java类和对象在堆内存中的分配情况

Memory Analyzer Tool (MAT)

常见内存泄露原因

Context对象泄漏

1、如果一个类持有Context对象的强引用,就需要检查其生存周期是否比Context对象更长。否则就可能发生Context泄漏。

2、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。

例如View#setTag(int, Object)的内存泄漏https://code.google.com/p/android/issues/detail?id=18273

3、把Context对象赋给static变量。

避免Context对象泄漏Checklist

1、检查所有持有对Context对象强引用的对象的生命周期是否超出其所持有的Context对象的生命周期。

2、检查有没有把View传出到View所在Context之外的地方,如果有的话就需要检查生命周期。

3、工具类中最好不要有Context成员变量,尽量在调用函数时直接通过调用参数传入。如果必须有Context成员变量时,可以考虑使用WeakReference来引用Context对象。

4、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。

5、  检查把Context或者View对象赋给static变量的地方,看是否有Context泄漏。

6、检查所有把View放入容器类的地方(特别是static容器类),看是否有内存泄漏。7、使用WeakHashMap也需要注意有没有value-key的引用。

7、尽量使用ApplicationContext。

Handler对象泄漏

1、发送到Handler的Message实际上是加入到了主线程的消息队列等待处理,每一个Message持有其目标Handler的强引用。

如我们通常使用的匿名内部类Handler

[java] view plaincopyprint?

  • <span style="font-size:18px;">HandlermHandler = new Handler() {
  • @Override
  • public voidhandleMessage(Message msg) {
  • mImageView.setImageBitmap(mBitmap);
  • }
  • }</span>


面是一段简单的Handler的使用。当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一
个Activity)的引用,因为View会依附着一个Activity。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出
现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络
请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有
Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收
(即内存泄露),直到网络请求结束(例如图片下载完毕)。另外,如果你执行了Handler的postDelayed()方法,该方法会将你的
Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条
MessageQueue -> Message -> Handler ->
Activity的链,导致你的Activity被持有引用而无法被回收。

当然,应为是Handler对外部持有引用的原因,我们就可以将Activity设置为一个弱引用,在不必要的时候,不再执行内部方法。

[java] view plaincopyprint?

  • <span style="font-size:18px;">/**
  • * @author zhoushengtao
  • * @since 2013-12-16 下午3:25:36
  • */
  • import android.app.Activity;
  • importandroid.content.Context;
  • importandroid.os.Handler;
  • importandroid.os.Message;
  • importjava.lang.ref.WeakReference;
  • publicclass WeakRefHandler extends Handler
  • {
  • WeakReference<Context> mWeakContext;
  • public WeakRefHandler(Context context)
  • {
  • mWeakContext = newWeakReference<Context>(context);
  • }
  • @Override
  • public void handleMessage(Message msg)
  • {
  • if((mWeakContext.get() instanceofActivity )&& ((Activity)mWeakContext.get()).isFinishing())
  • return ;
  • if(mWeakContext==null){
  • return ;
  • }
  • super.handleMessage(msg);
  • }
  • }</span>

2、Non-staticinner class 和anonymous class持有其outer class的引用。

Drawable.Callback引起的内存泄漏

Drawable对象持有Drawable.callback的引用。当把一个Drawable对象设置到一个View时,Drawable对象会持有该View的引用作为Drawable.Callback

避免Drawable.Callback引起内存泄漏

•       尽量不要在static成员中保存Drawable对象

•       对于需要保存的Drawable对象, 在需要时调用Drawable#setCallback(null).

其他内存泄漏

1、Android DigitalClock引起的内存泄漏http://code.google.com/p/android/issues/detail?id=17015

2、使用Map容器类时,作为Key 的类没有正确的实现hashCode和equal函数

其他内存泄漏

•       JNI程序中的内存泄漏

1、  Malloc/free。

2、  JNI Global reference

•       Thread-Local Variable

1、  相当于Thread对象的成员变量, 可以存储线程相关的状态

2、  如果thread是alive状态,那么Thread-Local中的对象就无法被GC。

进程内存占用监测工具

Dumpsys

•       $ dumpsys meminfo [pid]

Procrank + Shell脚本

•       #procrank

1、  VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)

2、  RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)

3、  PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)

4、  USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)

Shell脚本

#!/bin/bash

while true; do

adbshell procrank | grep "com.qihoo360.mobilesafe"

sleep1

done

当然,部分机型的sh都是经过第三方手机商精简过的,很多命令都用不了。Procrank,就是一个经常被精简掉的命令。

鉴于此:

自己写了一个小工具,检测内存的实时变化,

Github地址:https://github.com/stchou/JasonTest

小结

1.      保存对象前要三思

I.           对象本身有无隐含的引用

II.           保存后何时能够回收

2.      要了解常见的隐含引用

I.           anonymous class outer class

II.           View to context

3.      要通过各种工具检查内存占用是否有异常

4.      创建大对象时,要检查它的生命周期

/**
* @author zhoushengtao(周圣韬)
* @since 2014年5月21日 下午6:18:29
* @weixin stchou_zst

* @blog http://blog.csdn.net/yzzst
*/

Android内存性能优化(内部资料总结) eoe转载

时间: 2024-10-27 13:01:32

Android内存性能优化(内部资料总结) eoe转载的相关文章

Android内存性能优化(内部资料总结)

刚入门的童鞋肯能都会有一个疑问,Java不是有虚拟机了么,内存会自动化管理,我们就不必要手动的释放资源了,反正系统会给我们完成.其实Java中没有指针的概念,但是指针的使用方式依然存在,一味的依赖系统的gc,很容易就造成了内存的浪费.   Java基于垃圾回收的内存机制 Java的内存管理机制会自动回收无用对象所占用的内存,减轻手工管理内存的负担 1.C/C++: 从申请.使用.释放都需要手工管理 2.Java:无用的对象的内存会被自动回收 什么样的对象是无用的对象 1.Java通过引用来操作一

Android内存性能优化(内部资料总结) 转

刚入门的童鞋肯能都会有一个疑问,Java不是有虚拟机了么,内存会自动化管理,我们就不必要手动的释放资源了,反正系统会给我们完成.其实Java中没有指针的概念,但是指针的使用方式依然存在,一味的依赖系统的gc,很容易就造成了内存的浪费. Java基于垃圾回收的内存机制 Java的内存管理机制会自动回收无用对象所占用的内存,减轻手工管理内存的负担 1.C/C++: 从申请.使用.释放都需要手工管理 2.Java:无用的对象的内存会被自动回收 什么样的对象是无用的对象 1.Java通过引用来操作一个具

Android应用性能优化系列视图篇——隐藏在资源图片中的内存杀手

图片加载性能优化永远是Android领域中一个无法绕过的话题,经过数年的发展,涌现了很多成熟的图片加载开源库,比如Fresco.Picasso.UIL等等,使得图片加载不再是一个头疼的问题,并且大幅降低了OOM发生的概率.然而,在图片加载方面我们是否可以就此放松警惕了呢? 开源图片加载库能为我们解决绝大部分有关图片的问题,然而并不是所有! 首先,图片从来源上可以分成三大类:网络图片.手机图片.APK资源图片.网络图片和手机图片都在图片加载库功能的覆盖范围内,基本上不用开发者太操心,但是APK资源

Android app性能优化大汇总之内存性能优化

写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上把网上搜集的各种内存零散知识点进行汇总.挑选.简化后整理而成. 所以我将本文定义为一个工具类的文章,如果你在Android开发中遇到关于内存问题,或者马上要参加面试,或者就是单纯的学习或复习一下内存相关知识,都欢迎阅读.(本文最后我会尽量列出所参考的文章). 内存简介: RAM(random access memory)随机存取存储器.说白了就是内存. 一般Java在内存分配时会涉及到以下区域: 寄存器(R

Android App性能优化(一)之布局优化

当创建复杂布局的时候,我们会在xml 文件中添加大量的ViewGroup和View.伴随着每次迭代,View树的层次越来越深,界面加载速度越来越慢,消耗的内存也越来越多.当您的程序出现加载时短暂黑屏或横竖切换时短暂黑屏,抑或如内存溢出(OOM)之类的问题时,没准您的程序需要优化了. 那么如何让程序运行速度更快?响应更敏捷?优化布局是一个最基本的方法,本文将介绍最基本的优化布局方法. 1.使用ViewStub实现View的延迟加载. 很多情况下,xml布局文件中的部分View初始状态是设置为不显示

Android开发性能优化总结(一)

安卓开发应用首先要讲究良好的用户体验,如果一款软件卡顿现象严重,不流畅,经常崩溃,那么将给用户带来极不良好的体验,从而损失用户. 在实际开发和学习中,我总结了一下关于安卓性能的优化,供大家参考交流. 应用程序的性能问题体现在很多方面, 比如第一次启动速度慢,或者进入某一界面速度慢:动画执行过程不流畅,或者动画执行卡顿时间长:ListView列表滑动过程中卡顿,不流畅:应用程序自定义的某特定界面执行速度慢:响应某一用户事件时长时间无响应(ANR):操作数据库时,执行大量数据的增删改查操作,执行速度

Android客户端性能优化(魅族资深工程师毫无保留奉献)

本文由魅族科技有限公司资深Android开发工程师degao(嵌入式企鹅圈原创团队成员)撰写,是degao在嵌入式企鹅圈发表的第一篇原创文章,毫无保留地总结分享其在领导魅族多个项目开发中的Android客户端性能优化经验,极具实践价值! 即日起,嵌入式企鹅圈将在之前五个专栏(Linux内核驱动情景分析.资源紧缺型SOC嵌入式架构设计.嵌入式交叉工具链及其应用.嵌入式设计和编程.微信硬件平台和物联网解决方案)新增Android开发专栏!更多Android.Linux.嵌入式和物联网原创技术分享敬请

android App性能优化技巧浅谈

Android App性能优化,安卓App性能优化技巧,无论锤子还是茄子手机的不断冒出,Android系统的手机市场占有率目前来说还是最大的,因此基于Android开发的App数量也是很庞大的.那么,如何能开发出更高性能的Android App?相信是软件开发公司以及广大程序员们头疼的一大难题.今天,就给大家提供几个提高Android App性能的技巧. 高效地利用线程1.在后台取消一些线程中的动作 我们知道App运行过程中所有的操作都默认在主线程(UI线程)中进行的,这样App的响应速度就会受

Android应用性能优化

遇到的问题: 1)ANR 2)ListView 卡顿,不流畅 3)Activity启动慢 4)动画不流畅,启动前卡顿 5)自定义view启动慢 6)  OOM 7)数据库大量操作 8)长时间运行后,程序变慢 基本思想: 1)语言层解决问题,语法上提高性能 2)合理的数据结构和算法 3)布局优化,布局深度控制 4)工作线程与UI线程分离 5)合理的缓存机制 6)NDK合理使用 7)优化的SQL语句 8)使用工具,分析问题找出瓶颈 优化工具: view优化工具:hierarchy view 代码优化