JVM、Dalvik、ART

  1. Java程序执行过程

  1. 类加载器

JDK提供了三种类ClassLoader,分别是BootstrpLoader(根加载器)、ExtClassLoader(拓展类加载器)、 AppClassLoader(java默认的加载器) ,类加载动态性,先将基础类加载到JVM里,剩余的类会在需要的时候加载到JVM里。

  

 

  1. 双亲委托机制

加载一个类之前会判断该类是否被当前类加载器加载过,如果没有就委托它的父亲进行判断,先向上委托加载,到最高级,然后上面两级都不行的话,则递归往下

 

举例:1.加载A类     2. A类引用B类    3. A类和B类需要引用C类

<> A类当前线程的加载器加载线程中的第一个类

<> A类引用B类时,使用的是A类的类加载器去加载B类

<> A和B加载C时根据双亲委派机制,一旦发现有加载器加载过了便不再加载,直接读取。

扫描二维码关注公众号,回复: 6547182 查看本文章

 

 

  1. 运行时数据区

  1. 寄存器:线程独有、管理线程阻塞恢复挂起等操作、指向下一条被执行指令地址
  2. 方法区:全局共享、类(class)、成员变量、静态变量、静态方法、
  3. 本地方法栈:线程独有、执行native方法入口、使用的其它语言实现指令集解释器的时也会用到
  4. 堆:全局共享、存储对象实例、内置垃圾收集器(GC)
  5. 栈:线程独有、存取熟读快、方法运行时的数据存储区、局部变量、对象引用存储、私有的、

 

  1. 分代垃圾回收
  1. 年轻代

尽可能快速回收掉生命周期短的对象,一般配置一个Eden区和两个Survivor区(允许配置多个),大部分的对象在Eden区生成,当Eden区满了之后还存活的对象会被转移到Survivor区域(任意一个),当其中Survivor_1区域满了之后,会将存活的对象转移到Survivor_2,Survivor_2区域满了之后,此时从Survivor_1复制过来的对象仍存活的话,就会被复制到老年代区域里。

  1. 老年代

经历N次回收后仍存活的对象、生命周期较长

  1. 持久代

静态文件、Java类、方法(字节码),对垃圾回收没什么影响

 

  1. GC两种类型
  1. Minor GC

新对象创建时,并在Eden区申请空间失败时就会触发Minor GC。

  1. Full GC

在老年代和持久代区域被写满时,还有执行System.gc()时会被触发,时间长,导致卡顿,尽可能减少Full GC

 

  1. 标记-清除回收算法

标记:遍历所有的GC Roots,将所有GC roots可达的对象标记为存活的对象。

清除:停止程序运行,然后清除不可达的对象,然后恢复程序运行

 

 

  1. onLowMemory()&onTrimMemory()

在Android4.0以后,在内存紧张的时候,会回调OnLowMemory/OnTrimMemory,需要在回调方法中编写释放资源的代码。可以在资源紧张的时候,释放UI 使用的资源资:Bitmap、数组、控件资源。(好几年前开发有用过)经常会在该方法下执行System.gc,比较暴力,会发生卡顿现象。

 

  1. Dalvik虚拟机和ART虚拟机下GC策略的异同
  1. 在Dalvik虚拟机下所有的GC都是并发,ART运行时在内部创建了六个垃圾收集器。这六个垃圾收集器分为两组,一组支持并行GC,另一组不支持。
  2. 都是采用标记-清除算法的回收策略
  3. ART运行时对堆的划分更加细致,因而在此基础上实现了更多样的回收策略。不同的策略有不同的回收力度,力度越大的回收策略,每次回收的内存就越多,并且它们都有各自的使用情景。这样就可以使得每次执行GC时,可以最大限度地减少应用程序卡顿。

  • (Allocation Space、Zygote Space)  = (Active、Zygote)
  • Image space 存预加载的类
  • Zygote堆 存储创建Zygote进程启动时创建的对象
  • Active堆 负责应用程序分配内存
  • Large Object Space 离散地址集合,分配大对象(bitmap)

Dalvik虚拟机分配内存和GC的流程:

 

ART虚拟机GC类型:

  • kGcCauseForAlloc,分配内存的时候发现内存不够的情况下引起的GC ,并发,会发生卡顿
  • kGcCauseBackground, 当内存达到一定的阀值的时候会去出发GC,非并发,不会发生卡顿
  • kGcCauseExplicit, system.gc情况下触发,并发,会发生卡顿

 

ART的内存分配和GC流程比较复杂,等再啃多几次再分享,总体来说,按照谷歌的官方说法,ART会比Dalvik的内存分配效率提高10倍,GC效率提高了3倍,主要是ART单独为大对象开辟一块专门的内存区域,内置一套算法整理内存碎片,提高了效率。

 

补充上次分析中log里出现过跟GC相关的线程:

<> ReferenceQueueDaemon  引用队列守护线程

创建引用对象时会关联一个引用队列,当这个被引用的对象被GC回收时,这个线程会把引用对象放到关联队列里。便于应用程序知道那些引用对象的对象已经被回收了。

<> FinalizerDaemon  析构守护线程

对于重写了成员函数`            的对象,它们被GC决定回收时,并没有马上被回收,而是被放入到一个队列中,等待这个线程去调用它们的成员函数finalize,然后再被回收。

<> FinalizerWatchdogDaemon 析构监护守护线程

检测析构守护线程的执行

<> GCDaemon 并行GC线程

执行并行GC

 

拓展:

标记-压缩算法、复制算法、引用计数算法、ARTDalvik分配内存和GC的异同

猜你喜欢

转载自blog.csdn.net/qq_16247851/article/details/92811634