Android开发Android开发经验谈Android技术知识

Java虚拟机内存管理机制

2020-08-08  本文已影响0人  CDF_cc7d

JVM运行时数据区:

  1. 虚拟机栈
    虚拟机栈包含了局部变量表,操作数栈,动态链接,方法出口等。每个方法从执行到完成就是一个栈帧入栈到出栈的过程,出栈以后会返回一条字节指令的地址( returnAddress 类型,也就是回到方法刚开始执行的地方,程序计数器记录的位置)。局部变量表存放了基本数据类型,对象引用类型,returnAddress 类型。
    当执行的方法过多,压入栈的深度超过了规定的最大深度则会出现 StackOverFlowError;当然现在大部分的虚拟机都是可以扩展栈深度,一旦扩展深度的时候分配不了内存了,就会出现 OutOfMemoryError。
  2. 本地方法栈
    与虚拟机栈类似。不同点在于本地方法栈执行的是 native 方法,另外在执行本地方法栈的时候returnAddress则为null
  3. 方法区
    方法区存放着已被虚拟机加载的类信息,常量,静态变量以及即时编译后的代码
  4. 堆区
    堆区主要分为新生代区和老年代区,新生代区又可以分为 Eden 区, From Survivor 区, To Survivor 区。主要存放对象实例
  5. 程序计数器
    当前程序执行的行号指示器。指令进行分支,循环,跳转,异常处理,线程恢复都依赖程序计数器来完成。各个线程之间相互独立。

GC


堆内存


判断对象是否需要被回收

当然通过可达性分析法判断对象GC Roots不可达的时候,虚拟机也不会立刻去回收对象。GC 时先判断该对象是否重写了 finalize 方法。
如果重写了 finalize 方法,将会将对象放置到一个F-Queue的队列中,然后由虚拟机自动创建一个低优先级的Finalizer线程去执行它,(注意此时对象是可以通过再次与 GC Root 相连接的方式让自己重新"复活")之后 GC 会再次判断该对象是否 GC Roots 可达,此时如果依然不可达,那么才会真正的进行回收
如果没有重写 finalize 方法,那么虚拟机就会直接回收该对象
如果之前已经执行过一次 finalize 方法,那么虚拟机就会直接回收该对象。换句话说,一个对象在完整 的生命周期中只可能会调用一次 finalize 方法


回收算法

  1. 标记-清除算法:
    标记阶段:根据可达性分析法,标记出有被 GC Roots 引用的对象
    清除阶段:遍历整个堆区,找出那边没有被标记的对象(说明这些对象已经没有被引用了),然后进行GC操作


    标记-清除算法.jpg
  2. 复制算法:
    将对应的区块分成两个部分,每次只使用其中一部分。当要进行回收的时候,将这一块存活的对象复制到另一块中,然后清空当前块的对象

复制算法.jpg
  1. 标记-整理算法:
    标记方式与1相同,不同点是标记完成后将标记的对象和未标记的对象分开,让标记对象和未标记对象各自处在一个连续的内存分配空间上。这样就不需要遍历整个堆区,只要直接对其中一整块进行操作即可
标记-整理算法.jpg

标记-清除算法:内存回收以后碎片化比较严重,之后无法存放大内存对象,会造成频繁 GC
复制算法:效率最高,但是由于要牺牲掉一部分内存,所以导致内存使用率不高
标记-整理算法:相较于标记-清除算法优势很明显,不会出现碎片化的内存区块,但是相应的 GC 效率也就比标记-清除算法低了

三种算法各有优缺点,因此绝大部分虚拟机都是采用的分代收集算法。

上一篇 下一篇

猜你喜欢

热点阅读