android面试-java虚拟机运行时数据区(迅雷、久邦涉及到)

时间:2022-12-27 19:16:59

一、区域划分

java虚拟机运行时数据区主要分为以下几个区域管理:堆、本地方法栈、java虚拟机栈、方法区、程序计数器

二、详细介绍

想要了解以下的概念首先得有jvm的执行过程的概念:

1、什么是JVM内存:

Java源代码文件(.java)会被Java编译器编译为字节码文件(.class),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。可参考:一天一题

2、程序计数器

线程私有区域,记录当前线程执行到哪个指令,通俗一点来说就是用于下一条需要执行的字节码的跳转、分支等情况之后恢复需要计数器指向,可以理解为两个线程,A跳转B之后,B通过计数器来指向A的地址以此来恢复。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域


3、java虚拟机栈

java方法执行的内存模型,属于内存私有,每个方法执行时会创建一个栈帧,生命周期与线程周期同步,存储局部变量表、操作数栈、

     (1)局部变量表:用于存放编译期可知的各种基本类型、对象引用、returnAddress,听起来很抽象,理解就是可以使用局部变量表在编译期的时候确定在帧中需要分配大小

     (2)操作数栈:
用于进行一些引擎运算 不同于程序计数器,Java虚拟机没有寄存器,程序计数器也无法被程序指令直接访问。Java虚拟机的指令是从操作数栈中 而不是从寄存器中取得操作数的,因此它的运行方式是基于栈的而不是基于寄存器的。虽然指令也可以从其他地方取得操作 数,比如从字节码流中跟随在操作码(代表指令的字节)之后的字节中或从常量池中,但是 主要还是从操作数栈中获得操作数 意思即字节码的一些操作入栈等操作通过操作数栈来操作。
          
     (3)方法返回地址:PC程序计数器的值作为返回
注意这个区域可能出现的两种异常:一种是*Error,当前线程请求的栈深度大于虚拟机所允许的深度时,会抛出这个异常。制造这种异常很简单:将一个函数反复递归自己,最终会出现栈溢出错误(*Error)。另一种异常是OutOfMemoryError异常,当虚拟机栈可以动态扩展时(当前大部分虚拟机都可以),如果无法申请足够多的内存就会抛出OutOfMemoryError,如何制作虚拟机栈OOM呢

4、本地方法栈:

      本地方法栈与虚拟机栈所发挥的作用很相似,他们的区别在于虚拟机栈为执行Java代码方法服务,而本地方法栈是为Native方法服务。与虚拟机栈一样,本地方法栈也会抛出*Error和OutOfMemoryError异常。

5、堆:

实例对象在这里分配内存、GC垃圾收集器管理的主要区域。

     一、堆被分为新生代、老年代,

          新生代又划分为Eden、from survivor、to survivor=8:1:1,每次只会使用eden和一个survivor,即只能使用9/10


      二、垃圾回收方式:Minor GC、Full GC

     1、     minor
回收过程如下:
  当对象在 Eden ( 包括一个 Survivor 区域,这里假设是 from 区域 ) 出生后,在经过一次 Minor GC 后,如果对象还存活,并且能够被另外一块 Survivor 区域所容纳(上面已经假设为 from 区域,这里应为 to 区域,即 to 区域有足够的内存空间来存储 Eden 和 from 区域中存活的对象 ),则使用复制算法将这些仍然还存活的对象复制到另外一块 Survivor 区域 ( 即 to 区域 ) 中,然后清理所使用过的 Eden 以及 Survivor 区域 ( 即 from 区域 ),并且将这些对象的年龄设置为1,以后对象在 Survivor 区每熬过一次 Minor GC,就将对象的年龄 + 1,当对象的年龄达到某个值时 ( 默认是 15 岁,可以通过参数 -XX:MaxTenuringThreshold 来设定 ),这些对象就会成为老年代。 
但这也不是一定的,对于一些较大的对象 ( 即需要分配一块较大的连续内存空间 ) 则是直接进入到老年代。
       2、Full GC
 老年代的对象都是经过一次次的minor GC之后存活下来的,所以不会经常回收,full GC回收一次的代价是minor的十倍

     三、垃圾回收对象判定方法

       1、引用计算方法
            每当一个对象进行引用,引用计数器便+1,引用失效时-1.当计数=0时不会再被引用,可以回收
       互循环引用
       2、可达性分析算法
       算法过程如下:
        这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路 径称为引用链。当 一个对 象到GC roots没有任何引用链相连时,则证明此对象是不可用的。GC Roots是不可达的,将会被判 定为是可回收的对象。
即使被判定为回收对象,还没立即执行死刑,需要经过两次判定,
        1) 第一次判定是判定为回收对象,进行筛选,当对象没有覆盖finalize方法,或者finzlize方法已经被虚拟机调用过,虚拟机将 这两种情况都视 为“没有必要执行”,对象被回收。
        2)第二次标记
如果这个对象被判定为 有必要执行finalize()方法 ,那么这个对象将会被放置在一个名为:F-Queue的队列之中,并在稍后由一条虚拟机自动建立的、低优先级的Finalizer线程去执行。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束。这样做的原因是,如果一个对象finalize()方法中执行缓慢,或者发生死循环(更极端的情况),将很可能会导致F-Queue队列中的其他对象永久处于等待状态,甚至导致整个内存回收系统崩溃。

        Finalize()方法是对象脱逃死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象要在finalize()中成功拯救自己----只要重新与引用链上的任何的一个对象建立关联即可,譬如把自己赋值给某个类变量或对象的成员变量,那在第二次标记时它将移除出“即将回收”的集合。如果对象这时候还没逃脱,那基本上它就真的被回收了。

        四、垃圾回收算法:http://blog.csdn.net/wzhworld/article/details/78315589

6、 方法区:

存放的是类信息、常量、静态变量等。


三、垃圾回收器以及类加载机制

个人对于这部分没有去研究,所以就推荐一篇比较好的文章http://blog.csdn.net/huachao1001/article/details/51533132