JVM常见问题

JVM 常见问题总结

 

1. java虚拟机运行的流程

2. java虚拟机的核心设计思想

3. JAVA内存如何分配?

Java内存可以分为程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区这几个部分。其中程序计数器、Java虚拟机栈、本地方法栈属于线程私有,而Java堆和方法区属于线程共享区域。对于Java的堆内存可以划分为新生代和老年代。在新生代中划分为一个Eden区和两个Survivor区。创建一个Java对象时,会通过指针碰撞或空闲列表法为对象分配内存。而当我们访问一个对象的时候可以通过句柄或者直接地址的方式进行对象的访问。

4. 画出java运行时内存区结构图

  • 程序计数器

  • java虚拟机栈

  • 本地方法栈

  • java堆

  • 方法区

    1. 运行时常量池

  • 直接内存

前三个是线程私有的,java堆和方法区由所有线程共享。直接内存并不是java虚拟机运行时数据区域的一部分,但其中包括NIO类。

  1. 程序计数器可看作是当前线程所执行字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,是程序控制流的指示器,分支、循环、跳转、异常处理等基础功能都需要依赖该计数器;此外,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器;

  2. Java虚拟机栈的生命周期与线程相同,描述的是java方法执行的线程内存模型:每个方法执行的时候,java虚拟机就会同步创建一个栈帧来存储该方法的局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法从调用直至执行完毕的过程,就对应着一个栈帧再虚拟机中从入栈到出栈的过程。

  3. 本地方法栈: 和虚拟机栈类似,虚拟机栈为虚拟机执行java方法(也就是字节码服务),本地方法栈为虚拟机执行本地方法服务。

  4. java堆:虚拟机启动时创建。唯一目的就是存放对象实例,几乎所有对象实例都在这里分配内存。也是垃圾收集器管理的内存区域,因此也被称为(GC堆)

  5. 方法区:用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

5. 堆区如何分类

  • 设计者一般至少把Java堆划分为新生代和老年代两个区域。

  • 对于新生代,如果采用Appel标记-复制算法,会把新生代分为Eden和两个Survivor区,Eden:Survivor = 8:1。并一般用老年代来做分配担保。

  • G1收集器是基于Region的内存布局。

6. 堆与栈区别

  1. 堆存储的是对象。

  2. 栈对应的是调用的方法,每一个方法从调用到结束就对应着一个栈帧在栈中从入栈到出栈的过程。

7. 为什么要把字符串常量池放到堆区

8. java8方法区的变化

JDK7之前,HotSpot使用永久代来实现方法区时,类变量(也就是静态变量,被static修饰的变量)所使用的内存都应该在方法区中进行分配,方法区本身是一个逻辑上的区域。而在JDK之后,类变量会随着Class对象一起存放在Java堆中。

9. 判断对象已经无效

  • 引用计数器: 在对象中加一个引用计数器,每当有一个地方引用它,计数器就加1;引用失效时就减1;任何时刻计数器为0的对象就是不可能再被引用的。

  • 可达性分析: 通过一系列成为“GC roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径成为“引用链”,如果某对象到GC roots间没有任何引用链连接,或者说从GC roots到该对象不可达时,则证明此对象是不可能再被使用的。

10. 引用计数法实现原理

  1. 在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为0的对象就是不可能再被使用的。

  2. 虽然占用了一些额外的内存空间来进行计数,但原理简单,效率较高。但无法解决循环引用问题;

11. 哪些对象可以作为GC Root

GC roots应是一组活跃的引用;

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象

  2. 方法区中类静态属性引用的对象

  3. 方法区中常量引用的对象

  4. 本地方法栈中JNI(即一般说的native方法)中引用的对象

  5. java虚拟机内部的引用

  6. 所有被同步锁持有的对象

  7. 反应java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

12. GCRoot详细

  1. 固定可作为GC Roots的节点主要在全局性的引用与执行上下文中,尽管目标明确,但高效的查找到这些节点并不容易;

  2. 尽管可达性分析算法中耗时最长的查找引用链的过程已经可以做到与用户线程一起并发,但根节点枚举这一步骤都是必须暂停用户进程的,也就是Stop The World;而且根节点枚举还是必须在一个能保障一致性的快照中才得以进行。

  3. 在类加载动作完成的时候,HotSpot就会通过一种OopMap的数据结构把对象内什么偏移量上存放的是什么类型的数据给计算出来,在即时编译的过程中,也会在特定的位置记录下栈里和寄存器里哪些位置是引用。这样收集器在扫描时就可以直接得知这些信息了,并不需要真正一个不漏的从方法区等GC Roots开始查找。

  4. 在OopMap(一种可以直接得到那些地方存放着对象引用的数据结构)的帮助下,HotSpot可以快速准确的完成GC Roots枚举。

13. finalize()方法回收对象的两次标记过程

  • 即使在可达性分析中判定为不可达的对象,也不是非死不可的。要真正宣告一个对象死亡,最多会经历两次标记过程;

  1. 如果对象在进行可达性分析后发现没有和GC roots相连接的引用链,那它将会被第一次标记。随后进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。如果对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,那么虚拟机将这两种情况都视为没有必要执行。

  2. 如果对象被判定为有必要执行finalize()方法,那么该对象将会被放置到F-Queue队列之中。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后收集器将对F-Queue中的队列进行第二次标记。如果想拯救自己,只需重新与引用链上的任何一个对象建立关联即可。

14. Java四种引用及场景

  1. 强引用: 最传统的引用定义,指在程序代码中普遍存在的引用赋值。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象;

  2. 软引用ÿ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值