Memory Analyzer

版权声明:本文为博主原创文章,但部分内容来源网络,如有侵权,告知即删! https://blog.csdn.net/chenyuan_jhon/article/details/79855478

memory analyzer (内存分析)

android 内存优化关键点

(一:布局)
  1. 背景图的选择:
    1. 对于布局中的背景,能用color的尽量使用color,不要是图片代替。
    2. 对于规则的图片,能用shape画图的,尽量使用shape,不要使用图片
  2. 复用ItemView:
    1. 对于ListView、GridView、RecycleView可以使用item复用技术。
(二:变量声明)
  1. 少使用static修饰词:
    1. 内存分配:使用static修饰的对象只进行一次内存分配,假如有多
      个实例,则共享这个对象。
    2. 生命周期:static修饰的变量的在编译后所分配的内存会一直存在,因此可以直接通
      过类名.进行访问,程序消亡时,内存释放。
    3. 优化策略: 由于static修饰的生命周期和程序的生命周期同样长,因此,如果
      程序中过多的时候static修饰小的对象,或者修饰内存开销比较大的对象,就会造成内存
      过高使用,容易引发OOM.
  2. 字符串操作:
    1. 原因: java中对String的处理极为特殊,它可以不需要使用new关键字而直接
      创建对象,分配内存,如果在大量的字符串拼接时使用String,就会造成大量的内存分
      配,造成内存浪费
    2. 解决: 尽量使用StringBuffer提高效率。
(三:引用的传递)
  1. 弱化无关引用:
    1. 大多数情况下我们需要传递引用,但是无法确保被传递出去的引用在何时销毁,就会
      造成内存泄漏。如果知道哪些为无关引用,则可以将其设置为null,GC会自动回收。
  2. 善用SoftReference/WeakReference
    1. SoftReference:当内存吃紧的时候,系统会自动释放使用SoftReference包装的
      对象。
    2. WeakReference:如果对象消耗内存较大,那么对象使用完就需要释放,避免造成
      内存溢出,则可以使用WeakReference,当GC扫过那片内存或者内存吃紧时会被收回。
(四:未及时关闭造成的内存泄漏)
  1. Cursor、I/O流、BroadCastReceiver、Service、观察者模式等
    1. 这五种需要及时关闭或解绑。
(五:handler)
  1. 谨慎使用handler:

    1. 泄漏原因: 在处理异步操作的时候,handler+thread是个不错的选择。但是
      handle运行于主线程,负责处理MessageQueue的消息,但是当handler还有消息需要
      处理或者线程未执行完,activity页面已经结束的情况下,该activity的引用并不会
      被回收,这就造成了内存泄漏。
    2. 解决方案:

      1. 在onDestroy方法中关闭线程。
      2. 在onDestroy方法中调用handler.removeCallbacksAndMessages(null)
        取消所有的消息处理。
      3. 声明handler的内部类为static,需要结合WeakReference使用,因为static
        内部类不能持有外部类的引用,所以需要把外部类以弱引用的形式传递进来。
        public class Main2Activity extends AppCompatActivity {
        
            private static class myHandler extends Handler {
                private WeakReference<Main2Activity> mActivity;
                public myHandler(Main2Activity activity) {
                    mActivity = new WeakReference<>(activity);
                }
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Main2Activity activity = mActivity.get();
                    if (activity != null) {
                        //to do something
                        Log.i("aaa", "handler something...");
                    }
                }
            }
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main2);
                final myHandler myHandler = new myHandler(this);
                myHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        // to do something
                        Log.i("aaa", "Runnable");
                        myHandler.sendEmptyMessage(1);
                    }
                }, 1000 * 6);
            }
        }
        
(六:Bitmap)
  1. 谨慎处理Bitmap:
    1. 法则一:使用完及时释放recycle()
    2. 法则二:可适当放缩,通过BitmapFactory.Options.inSampleSize属性控制。
    3. 法则三:避免根据像素去分配内存,如果只需要获取Bitmap的属性,可以使用Bit
      mapFactory.Options.inJustDecodeBounds
      属性。
    4. 法则四:在加载网络图片时,尽量使用SoftReference或者WeakReference并进行
      本地缓存。
    5. 法则五:使用大牛的框架。
(七:线程)
  1. 线程操作:
    1. 及时关闭
    2. 控制数据
    3. 使用线程池
(八:activity中的耗时操作)
  1. 耗时的非静态内部类

    1. 原因: 在activity中,非静态内部类持有activity的引用,如果activity
      已经关闭,而内部类的耗时操作仍在继续,那么activity的引用将无法销毁,造成内存
      泄漏。比如说线程,或者网络请求等。
  2. 去除不必要的抽象:

    1. 抽象的成本很高,执行他们需要更多的代码,需要更多的时间和更多的RAM来将代码
      映射到内存中,因此需要去除没有必要的抽象。
  3. 谨慎使用service

(九:数据结构相关)
  1. SparseArray和ArrayMap替代HashMap
    1. HashMap原理
    2. SparseArray原理
    3. ArrayMap原理
    4. 参考:https://blog.csdn.net/u010687392/article/details/47809295

参考:

https://blog.csdn.net/tuke_tuke/article/details/52316285


内存分析工具

MAT(Memory Analyzer Tools)
  1. 获取Dump文件既堆转储文件:格式为hprof
    1.打开android studio 运行你的程序,点击Tools->Android->Android Device
    Monitor->选中DDMS,选中你的程序,选中左边的Dump HPROF File ,保存生成的文件

  2. 转换Dump文件:

    1. 工具所在位置:通过DDMS获取的.hprof文件需要转换才能被MAT识别,android SDK
      中有hprof-conv.exe的程序,可以转换这个文件,位置: Sdk\platform-tools
      下。
    2. 转换:在Sdk\platform-tools目录下打开CMD,输入命令:
      hprof-conv xxx.hprof yyy.hprof,即可转换文件,
      注意: 从DDMS获取的.hprof文件一定要放在Sdk\platform-tools目录下。
  3. 分析转换后的文件,格式仍为hprof

    1. 导入hprof文件以后会出现两个界面,一个是Overview(概览),一个是default
      reports(默认报告)。

      扫描二维码关注公众号,回复: 3292553 查看本文章
      1. Overview:展示的是这个Dump文件一个总体信息,通过这个圆饼图可以查看各个
        部分所占用的内存情况。圆饼图下面分别是actions、reports和step by step,
        actions 中包含了四个比较重要的功能,最常用的是Histogram

      1. Histogram: 它按类名将所有的实例对象列出来,表头可以使用正则表
        达式匹配。

      1. 此处有两个Main2Activity,说明有内存泄漏,鼠标右键点击,选择list
        objects->with incoming references,点开可以查看是谁持有Main2Activity
        对象的引用造成了泄漏。例如本例是(为了测试故意使用handler来造成内存泄漏)
        :handler,泄漏原因和所在线程都显示出来了

      1. 快速查找: 右键点击->Path to GC roots->exclude all
        phantom/weak/soft etc. reference(排除所有的虚、弱、软引用)

    2. 对比查找原因:

参考:

https://blog.csdn.net/aaa2832/article/details/19419679


基础

java中内存是什么分配的?(Think in java)
  1. 寄存器:这是最快的存储区,位于处理器内部。寄存器极其有限,根据需求分配,java无法
    控制,但C、C++可以建议建议寄存器的分配方式。
  2. 堆栈:速度仅次于寄存器,位于RAM(随机访问存储器)。堆栈可以通过堆栈指针从处理器
    那里获得直接的支持。堆栈指针上移释放内存(可以想象activity的栈),堆栈指针下移分配
    内存。程序创建时,java必须知道存储在堆栈中的所有项的确切的生命周期,以便上移下移指
    针,所以这就限制了程序的灵活性。java中对象的引用存储在堆栈中,但是java对象本身并
    不在堆栈中。

    优点: 速度快
    缺点: 需要知道确切的生命周期才能分配内存

  3. 堆:通用的存储区,也位于RAM中。堆不需要知道存储数据在堆中的存活的时间,因此灵活
    性更强。使用时只需要new一个对象,堆就会自动进行内存分配,但是付出的代价是:进行内存
    的分配和清理要发费更长的时间。java中所有的对象都存储在堆中。

    优点: 灵活
    缺点: 速度慢

  4. 常量池:存放代码中的常量。

  5. 非RAM存储:如果有些数据完全存活于程序之外,那么他们可以不受程序控制。比如:流对
    象和持有话对象。

java中基本数据类型的分配
  1. java中通常new一个很小的基本数据类型在堆中往往不是很有效,因此对于基本数据类型,
    java通常不用new来创建变量,而是创建一个非引用的变量,这个变量直接存储值,并置于堆栈
    中,因此更加高效。
  2. java中每种基本类型都对应有封装类型,封装类型可以在堆中创建一个非基本对象,用来
    表示对应的基本数据类型。
强引用、弱引用

https://blog.csdn.net/mazhimazh/article/details/19752475

Garbage Collection(GC)

  1. Garbage Collection回收的是哪部分内存:负责回收堆(heap)内存中没有被使用的对象,
    既这些对象没有被引用。

更新中。。。。
https://blog.csdn.net/peterwin1987/article/details/7571808

猜你喜欢

转载自blog.csdn.net/chenyuan_jhon/article/details/79855478
今日推荐