美文网首页
性能优化(三,内存泄漏)

性能优化(三,内存泄漏)

作者: 腊鸡程序员 | 来源:发表于2019-05-04 10:38 被阅读0次
flag.jpg

要做内存优化,首先我们要了解一下我们写的代码,在java虚拟机中是怎样分配内存的,static final 变量,局部变量,对象实例,等等,他们在JVM中如何使用内存以及何时被回收,以及GC是如何回收的

JVM的内存管理方式

java虚拟机将内存分为两大块,分别是线程私有区和共享数据区


image.png
线程私有区

线程私有区分为3个部分,分别是程序计数器,虚拟机栈和本地方法栈.

  1. 程序计数器用来指示执行下一行代码的地址,每个线程都有自己的程序计数器,程序计数器没有oom.
  2. 虚拟机栈即我们平时所说的栈,用来存放局部变量,方法返回地址等等,java虚拟机规范中定义了outofmemory和stackoverflow异常.
  3. 本地方法栈是jni c,c++代码的存放区域.java虚拟机规范中定义了outofmemory和stackoverflow异常.hotspotVM把虚拟机栈和本地方法栈合并为一个栈区.
共享数据区

共享数据区又分为两大块区域,他们分别是方法区和堆区.

  1. 方法区存放字面量和符号引用,即类信息,常量,静态变量,即时编译器编译后的代码,特殊的class对象.有oom异常.
    方法区也叫运行时常量池
    字面量: public static final ,java常量
    符号引用: 方法名,类,接口全名
  2. 堆区是jvm最大的一块内存区域,是GC的主战场.也是我们进行内存优化主要的区.有oom异常.存放对象实例,数组内容.


    image.png
GC垃圾回收器

java语言最大的两个特点,一个在于write a time,run any where.即跨平台性.一个在于垃圾回收机制,不用程序员自己去分配和回收内存.而是又jvm定时GC.这也造成了一些不规范代码引起的内存泄漏.我们需要去了解GC的回收机制,才能更好的解决内存优化问题.
那么GC是如何进行垃圾回收的呢?

GC如何确定一块内存是否应该回收
  1. 引用计数算法
    原理:
    引用计数算法很好理解,即如果有一个引用指向这块内存,这块内存的引用计数就+1,当GC扫描时,如果一块内存的引用计数为0,说明这块内存没有被使用,认为可以回收.
    应用:
    ios6中的手动计数mrc和自动计数arc
    cocos2dx
    缺点:
    当两个对象相互引用时,计数永远不会为0.即使这两个对象不再被使用,也不会被回收.

  2. 可达性分析算法


    可达性分析.png

原理:
如上图,JVM会将生命周期比较长的对象作为GC Root,比如虚拟机栈正在运行使用的对象,静态属性,常量,JNI引用的对象. 判断一个对象是否能被回收,就看这个对象到GC Root是否可达
GC是需要两次扫描才会回收对象,第一次扫描标记是否可回收,第二次扫描才会回收.所以我们可以用finalize救活丢失引用的对象.
例如:
static App a;
@Overrride
protected void() throws Throwable{
super.finalize();
a = this;
}

  1. 回收和引用类型的关系
    强引用:Object o = new Object();
    软引用:SoftReference,当内存不足时回收,用于存放重要性不是很强单又不能随便被清除的对象,比如图片,当切换到后台时,内存不足可以回收这些图片,切换到前台时再次创建.
    弱引用:WeackReference,GC第一次扫描时标记,第二次扫描时直接回收.
    虚引用:PhantomReference,幽灵 幻影引用,不对内存造成影响,用于跟踪GC的回收通知
内存泄漏

当由于代码的不规范,造成一个对象没有被使,但是由于引用问题没有被回收,就会造成内存泄漏,当虚拟机没办法开辟新的内存时,就会引起oom异常.

我们可以用一些工具来查看程序运行时的内存占用情况,进而发现问题,解决问题.

  1. Android Profile 的使用,


    image.png

    使用这个图标运行程序,会出现程序运行中的内存分配情况


    image.png
  2. Mat工具
    下载: https://www.eclipse.org/mat/downloads.php
    转换命令 hprof-conv -z src dst
    select * from instanceof android.app.Activity

    image.png

造成内存泄漏的代码可能是由于第三方或者安卓源码引起的,这是需要用反射去关闭第三方或者源码中多余的引用.
也有可能是自己代码引起的,这就需要在平时写代码中多多注意.

相关文章

网友评论

      本文标题:性能优化(三,内存泄漏)

      本文链接:https://www.haomeiwen.com/subject/qcqvnqtx.html