内存优化

2019-11-19  本文已影响0人  放肆滴微笑

内存优化,主要来处理:内存泄露,内存抖动

Java虚拟机

运行时数据区域分为

  1. 共享数据区
    1.方法区
    • ClassLoader加载类信息,常量、静态变量、类信息,编译后的代码
    • 运行时常量池,字面量public static final java常量,符号引用,类,接口全名,方法名
    1. java堆
    • 虚拟机能管理的最大一块内存,gc主战场
    • 对象实例,数组的内容
  2. 线程私有区
    1. 程序计数器,相当于一个执行代码的指示器,用来确认下一行代码的地址,每个线程都会有一个。也就是一个变量,存储下一行代码的内存地址,如下绿色


      image.png
    2. 虚拟机栈,java虚拟机规范中定义了outofmemory和stackoverflow异常
    3. 本地方法栈,java虚拟机规范中定义了outofmemory和stackoverflow异常
image.png image.png

内存泄露

产生原因
一个长生命周期的对象持有一个短生命周期对象的引用,通俗讲就是该回收的对象,因为引用问题没有被回收,最终OOM

Android Profiler的使用

  1. Run菜单下的profile XXX 或者 image.png
  2. 在图型用户界面上选择要分析的一段内存
    • Allocations: 动态分配对象个数
    • Deallocation:解除分配的对象个数
    • Total count :对象的总数
    • Shallow Size:对象本身占用的内存大小
    • Retained Size:GC回收能收走的内存大小
      下载出来


      image.png

Mat工具使用
Mat下载地址

  1. 根据上面下载的文件,转换profile文件格式,打开sdk/platform-tools/hprof-conv文件,创建一个临时文件夹,cmd中找到,执行转换命令 hprof-conv -z 源文件 目标文件
  2. 打开文件 File-->Open Heap Dump...
  3. 选择Histogram


    image.png
  4. 输入查找的类名,就可以进行分析了
    image.png

解决方案

内存抖动

内存的频繁分配与回收,如果分配速度大于回收速度,最后也会OOM
标记清除算法Mark-Sweep


image.png

复制算法Copying


image.png

标记压缩算法Mark-Compact


image.png

强软弱虚引用

区别
虚引用只要gc扫过去,就会回收,是拿不到数据,只能从队列中获取
弱引用,可以拿到数据,gc扫过后拿不到数据,只能从队列中获取

# 虚引用
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
Object obj = new Object();
//虚引用
PhantomReference phantomReference = new PhantomReference(obj,referenceQueue);

//拿到虚引用的对象
System.out.println("phantomReference   obj:"+phantomReference.get());
//获取一个对象
System.out.println("referenceQueue   poll"+referenceQueue.poll());

obj = null;
System.gc();
Thread.sleep(2000);

//拿到虚引用的对象
System.out.println("phantomReference   obj:"+phantomReference.get());
//获取一个对象
System.out.println("referenceQueue   poll"+referenceQueue.poll());

通过打印发现,虚引用在放入引用中,就不能获取到对象,引用队列开始也不能获取,通过gc后,则引用无法获取对象,引用队列则记录了对象

phantomReference   obj:null
referenceQueue   pollnull
phantomReference   obj:null
referenceQueue   polljava.lang.ref.PhantomReference@32a1bec0

# 弱引用

ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
Object obj = new Object();

WeakReference weakReference = new WeakReference(obj,referenceQueue);
//拿到弱引用的对象
System.out.println("weakReference   obj:"+weakReference.get());
//获取一个对象
System.out.println("referenceQueue   poll"+referenceQueue.poll());

obj = null;
System.gc();
Thread.sleep(2000);

//拿到弱引用的对象
System.out.println("weakReference   obj:"+weakReference.get());
//获取一个对象
System.out.println("referenceQueue   poll"+referenceQueue.poll());

通过打印 发现,弱引用在gc回收前,可以获得引用对象,引用队列中没有对象,gc后,不能获得引用对象,引用队列中可以获得之前的引用对象

weakReference   obj:java.lang.Object@32a1bec0
referenceQueue   pollnull
weakReference   obj:null
referenceQueue   polljava.lang.ref.WeakReference@22927a81

内存优化解决方案,编码习惯

public static final int RECTANGLE=0;
public static final int TRIANGLE=1;
public static final int SQUARE=2;
public static final int CIRCLE=3;

//flag=true ,只能选择常量的一种负值不能| false 则可以|
@IntDef(flag=true,value={RECTANGLE,TRIANGLE,SQUARE,CIRCLE})
@Target({ElementType.PARAMETER,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Model{

}

private @Model int value=RECTANGLE;
public void setShape(@Model int value){
    this.value=value;
}
@Model
public int getShape(){
    return this.value;
}
上一篇 下一篇

猜你喜欢

热点阅读