zoukankan      html  css  js  c++  java
  • 内存优化

    内存溢出和内存泄漏
    内存溢出:就想杯子里得水满了,就溢出了。内存溢出就是分配的内存被用光了,不够用了。

    内存泄露:就如同杯子里面有石子,导致杯子里面的一部分空间没有被利用,在APP中内存泄露就是指该被回收的内存没有被回收,导致一部分内存一直被占着,可利用内存变少了。当泄露过多 时,可利用的内存越来越少,就会引起内存溢出了。

    内存优化分为:【一个本质和三个知识点】 
    本质:对象的引用未被释放,导致对象本身无法被有效的回收。 
    三个知识点:内存泄漏、内存溢出、内存优化工具。

    【内存泄漏】 

    1.单例造成的内存泄漏

    因为单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。所以当需要传入一个context,应传入Application的Context

    例如:public class AppManager {
    private static AppManager instance;
    private Context context;
    private AppManager(Context context) {
    this.context = context.getApplicationContext();
    }
    public static AppManager getInstance(Context context) {
    if (instance != null) {
    instance = new AppManager(context);
    }
    return instance;
    }
    }

    2.匿名内部类/非静态内部类创建静态实例造成的内存泄漏

    原因:内部类持有对象引用,导致无法释放,比如各种回调 
    优化:保持生命周期一致,改为静态实例+对象的弱引用方式(WeakReference)

    例如:public class MainActivity extends AppCompatActivity {
    private static TestResource mResource = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if(mManager == null){
    mManager = new TestResource();
    }
    //...
    }
    class TestResource {
    //...
    }
    }
    正确的做法为:将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例,如果需要使用Context,请使用ApplicationContext 。

    3.Handler造成的内存泄漏

    Handler持有Activity的引用,其发送的Message中持有Handler的引用,当队列处理Message的时间过长会导致Handler无法被回收 

    正确的写法:public class MainActivity extends AppCompatActivity {
    private MyHandler mHandler = new MyHandler(this);
    private TextView mTextView ;
    private static class MyHandler extends Handler {
    private WeakReference<Context> reference;
    public MyHandler(Context context) {
    reference = new WeakReference<>(context);
    }
    @Override
    public void handleMessage(Message msg) {
    MainActivity activity = (MainActivity) reference.get();
    if(activity != null){
    activity.mTextView.setText("");
    }
    }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTextView = (TextView)findViewById(R.id.textview);
    loadData();
    }

    private void loadData() {
    //...request
    Message message = Message.obtain();
    mHandler.sendMessage(message);
    }

    @Override
    protected void onDestroy() {
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
    }
    }
    优化:静态实例+弱引用(Weakrefrence)方式 ,销毁对象时候清空队列里的Message使用mHandler.removeCallbacksAndMessages(null);是移除消息队列中所有消息和所有的Runnable。当然也可以使用mHandler.removeCallbacks();或mHandler.removeMessages();来移除指定的Runnable和Message。

    4.线程造成的内存泄漏

    原因:线程持有对象的引用在后台执行,与对象的生命周期不一致 
    优化:静态实例+弱引用(Weakrefrence)方式,使其生命周期一致
    例如:new Thread(new Runnable() {
    @Override
    public void run() {
    SystemClock.sleep(10000);
    }
    }).start();
    上面的Runnable是一个匿名内部类,因此它们对当前Activity都有一个隐式引用。如果Activity在销毁之前,任务还未完成, 那么将导致Activity的内存资源无法回收,造成内存泄漏。正确的做法还是使用静态内部类的方式
    正确写法:static class MyRunnable implements Runnable{
    @Override
    public void run() {
    SystemClock.sleep(10000);
    }
    }
    //——————
    new Thread(new MyRunnable()).start();
    5.资源未关闭造成的内存泄漏
    对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。当我们不再使用Bitmap对象的时候一定要执行recycler方法,这里需要指出的是当我们在代码中执行recycler方法,Bitmap并不会被立即释放掉,其只是通知虚拟机该Bitmap可以被recycler了。在加载网络图片的时候,使用软引用或者弱引用并进 行本地缓存
    6. 使用了属性动画或循环动画
    在Activity中使用了属性循环动画,在onDestroy()方法中未正确停止动画

    7.集合操作不当引发的内存泄漏 
    原因:集合只增不减 
    优化:有对应的删除或卸载操作

    内存溢出: 
    原因: 
    1.内存泄漏长时间的积累 
    2.业务操作使用超大内存 
    优化: 
    1.调整图像大小后再放入内存、及时回收 
    2.不要过多的创建静态变量,由于static声明变量的生命周期其实是和APP的生命周期一 样的,有点类似与Application。如果大量的使用的话,就会占据内存空间不释放,积少成多也会造成内存的不断开销,直至挂掉。static的合理 使用一般用来修饰基本数据类型或者轻量级对象,尽量避免修复集合或者大对象,常用作修饰全局配置项、工具类方法、内部类

    针对static的解决方案:

       <1>应该尽量避免static成员变量引用耗费过多的实例,比如Context。

       <2>Context尽量使用ApplicationContext,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。

       <3>使用WeakRefrence代替强引用。比如可以使用WeakRefrence<Context>mContextRef;

    3.String字符串优化

    最常见的例子就是当你要频繁操作一个字符串时。使用StringBuffer代替String。

    还比如:使用int数组而不是Integer数组。

    4.UI视图优化

    减少视图层级,可以有效的减少内存消耗,因为视图是一个树形结构,每次刷新和渲染都会遍历一次

    (1)ViewStub标签可以使UI在特殊情况下,只管效果类似于设置View的不可见性,但是其最大意义在于被整各标签所包裹的vIEWS在默认状态下不会占用任何内存空间。

    (2)Merge

    单独将<merge/>标签做个介绍,是因为它在优化UI结构时起到很重要的作用。目的是通过删减多余或者额外的层级,从而优化整个Android Layout结构。核心功能就是减少冗余的层次从而达到优化UI的目的

    (3)include

    可以通过这个标签直接加载外部的xml到当前结构中,是复用UI资源的常用标签

    (4)尽量使用相对布局

    5.ListView优化

    (1)Item布局,层级越少越好,使用hierarchyview工具查看优化

    (2)复用convertView

    (3)使用ViewHolder

    (4)item中有图片时,异步加载

    (5)快速滑动时,不加载图片

    (6)item中有图片时,应对图片进行适当的压缩

    (7)实现数据的分页加载

    6.性能优化工具的使用

    MAT,LearkCanary,Memory Monitor,Allocation Tracking,Heap Tool,hierarchyviewer布局检测工具

    内存优化工具: 
    Square:LeakCanary、MAT等

  • 相关阅读:
    cat
    cal
    API、ABI区别
    html 实体转换为字符:转换 UEditor 编辑器 ( 在 ThinkPHP 3.2.2 中 ) 保存的数据
    IDEA突然无法运行
    Java实现 蓝桥杯 算法提高 成绩排名
    Java实现 蓝桥杯 算法提高 成绩排名
    Java实现 蓝桥杯 算法提高 成绩排名
    Java实现 蓝桥杯 算法提高 Monday-Saturday质因子
    Java实现 蓝桥杯 算法提高 Monday-Saturday质因子
  • 原文地址:https://www.cnblogs.com/evolutionoflicorice/p/10191866.html
Copyright © 2011-2022 走看看