android内存优化总结

一、内存优化总结

 1、Dalvik & ART

Android在4.4之前一直使用的Dalvik虚拟机作为App的运行VM的, 4.4中引入了ART作为开发者备选, 5.0起正式将ART作为默认VM了

7.0后采用了混合编译

2、每个应用(进程)最大可用内存(dalvik)

adb shell getprop dalvik.vm.heapgrowthlimit

adb shell getprop dalvik.vm.heapsize(设置了android:largeHeap=true后)

3、Generational Heap Memory内存模型的概述

在Android和Java中都存在着一个Generational(读音:[ˌdʒenəˈreɪʃənl]) Heap Memory模型,系统会根据内存中不同的内存数据类型分别执行不同的GC操作。Generational Heap Memory模型主要由:Young Generation(新生代)、Old Generation(旧生代)、Permanent(读音:[ˈpɜ:rmənənt]) Generation三个区域组成,而且这三个区域存在明显的层级关系。所以此模型也可以成为三级Generation的内存模型。 

Generational Heap Memory的模型

其中Young Generation区域存放的是最近被创建对象,此区域最大的特点就是创建的快,被销毁的也很快。当对象在Young Generation区域停留的时间到达一定程度的时候,它就会被移动到Old Generation区域中,同理,最后他将会被移动到Permanent Generation区域中。

三级内存模型的移动 

在三级Generation内存模型中,每一个区域的大小都是有固定值的,当进入的对象总大小到达某一级内存区域阀值的时候就会触发GC机制,进行垃圾回收,腾出空间以便其他对象进入。

触发GC机制

不仅如此,不同级别的Generation区域GC是需要的时间也是不同的。同等对象数目下,Young Generation GC所需时间最短,Old Generation次之,Permanent Generation 需要的时间最长。当然GC执行的长短也和当前Generation区域中的对象数目有关。遍历查找20000个对象比起遍历50个对象自然是要慢很多的。

4、常用的内存优化方法

1)、ListView和GridView的item缓存

2)、避免布局的多层嵌套,减少过度绘制

    在手机开启“设置”->“开发者选项”->"调试GPU过度绘制" 

3)、页面背景和图片加载

    在布局和代码中设置背景和图片的时候,如果是纯色,尽量使用color;如果是规则图形,尽量使用shape画图;如果稍微复杂点,可以使用9patch图;如果不能使用9patch的情况下,针对几种主流分辨率的机型进行切图。

4)、线程

线程不再需要继续执行的时候要记得及时关闭,开启线程数量不易过多,一般和自己机器内核数一样最好,推荐开启线程的时候,使用线程池。

5)、String/StringBuffer

   当有较多的字符创需要拼接的时候,推荐使用StringBuffer

6)、避免内存抖动

  •    尽量避免在循环体内创建对象,应该把对象创建移到循环体外。
  •    注意自定义View的onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象。
  •    当需要大量使用Bitmap的时候,试着把它们缓存在数组中实现复用。
  •    对于能够复用的对象,同理可以使用对象池将它们缓存起来。

二、内存泄漏检测常用工具

1、android Monitor/Memory Profiler(android studio 3.0 用的Memory Profiler)

2、DDMS  

3、Memory Analyzer Tool (MAT)

4、LeakCanary 


 三、常出现的内存泄漏点

1、MediaPlayer导致的内存泄漏的问题

MediaPlayer 在执行release时未对源码中的mSubtitleController引用的context 进行释放,造成内存泄漏

 @Override

  protected void onDestroy() {

    super.onDestroy(); 

   ReleasePlayer();

 /** * 释放播放器资源 */ 

 private void ReleasePlayer() {

    if (mPlayer != null) {

      mPlayer.stop();

      mPlayer.reset();

      mPlayer.release(); 

      mPlayer = null; 

   } 

}

2、VideoView导致的内存泄漏的问题

android 6.0以前AudioManager用的Context是当前传入的,当activity finish之后 AudioManager依然保持对它的引用,所以就内存泄漏了,6.0后改用ApplicationContext修复了此问题,动态创建VideoView可解决此问题。

mVideoView =  new VideoView(getApplicationContext());
RelativeLayout.LayoutParams p =  new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
p.addRule(RelativeLayout.CENTER_IN_PARENT);
mVideoView.setLayoutParams(p);
((RelativeLayout)findViewById(R.id.videoContainer)).addView(mVideoView,  0)

 

3、handler 导致的内存泄漏

如果handler内持有了activity的引用,在activity finish时 handler内的任务未执行完成,将会出现内存泄漏。

//方法一:可以使用静态内部类+弱引用的方法解决。 

private static class MyHandler extends Handler { 

     private WeakReference<Activity> reference;

    public MyHandler(Activity activity) { 

   reference = new WeakReference<Activity>(activity);

 @Override

  public void handleMessage(Message msg) {

    super.handleMessage(msg);

   LeakActivity activity = (LeakActivity) reference.get(); 

    if (activity != null) { 

        activity.xxxxx();

   else {

        Logger.d("activity = null");

    }

}}

 private final Handler mHandler = new MyHandler(this);

//方法二:在 onDestroy中移除handler消息

 @Override

  protected void onDestroy() { 

    super.onDestroy();

   mHandler.removeCallbacksAndMessages(null);

}

4、单例导致内存泄露

 Activity在调用destory时,单例对象中还在持有此activity的引用,就会造成系统无法回收activity内存,出现内存泄漏。

由于Application 的Context的生命周期和应用一样长,可以使用Application Context解决此问题。

5、静态变量导致内存泄露

比如用静态变量声明一个Dialog 、View 、Activity等,也就是当static声明的对象中包含了当前activity的引用,就可能出现内存泄漏。

public class MainActivity extends Activity{  

public static Context mContext;  

   @Override  

   protected void onCreate(Bundle savedInstanceState) {  

   super.onCreate(savedInstanceState);  

   setContentView(R.layout.activity_main);  

    mContext = this;  

 }  

}  

 

6、非静态内部类和匿名类导致内存泄露

   由于非静态内部类和匿名类隐式持有当前activity的引用,造成了内存泄漏。

7、未取消注册或回调导致内存泄露

    比如我们在Activity中注册广播,如果在Activity销毁后不取消注册,那么这个刚播会一直存在系统中,同上面所说的非静态内部类一样持有Activity引用,导致内存泄露。因此注册广播后在Activity销毁后一定要取消注册。

8、Timer和TimerTask导致内存泄露

    TimerTask对象在和Timer的schedule()方法配合使用的时候极容易造成内存泄露。
要在合适的时候进行Cancel即可,比如在onDestroy中做cancel 操作。

9、集合中的对象未清理造成内存泄露

10、资源未关闭或释放导致内存泄露

  对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的代码,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。 

11、属性动画造成内存泄露

   如果在Activity中播放此类动画且没有在 onDestroy中去停止动画,那么动画会一直播放下去,尽管已经无法在界面上看见动画效果了,并且这个时候 Activity的 View会被动画持有,而View又持有了Activty,最终Activity无法释放。下面的动画是无限动画,会泄露当前的Activity,解决方法是在Activity的onDestroy中调用animator.cancel()来停止动画。

12、WebView造成内存泄露

1)为加载WebView的界面开启新进程,在该页面退出之后关闭这个进程。

2)在onDestroy方法中执行(待验证)

 

protected void onDestroy() {
 if( mWebView!= null) {
     // 如果先调用destroy()方法,则会命中if (isDestroyed()) return;这一行代码,需要先onDetachedFromWindow(),再  // destory()
    ViewParent parent = mWebView.getParent();
    if (parent !=  null) {
        ((ViewGroup) parent).removeView(mWebView);
    }
    mWebView.stopLoading();  // 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错
    mWebView.getSettings().setJavaScriptEnabled( false);
    mWebView.clearHistory();
    mWebView.clearView();
    mWebView.removeAllViews();
    mWebView.destroy();
  }
  super. on Destroy();
}




参考:

http://blog.csdn.net/u011326979/article/details/50748181

http://blog.csdn.net/huang_rong12/article/details/51628264

https://www.jianshu.com/p/5db05db4f5ab

http://blog.csdn.net/vshuang/article/details/39647167

https://www.cnblogs.com/purpleraintear/p/6046441.html

http://blog.csdn.net/qq_23191031/article/details/63685756

https://www.jianshu.com/p/ab4a7e353076

http://blog.csdn.net/gaugamela/article/details/79027538

http://blog.csdn.net/zlgzh/article/details/70171435

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值