jvm-questions

  1. 内存模型以及分区,需要详细到每个区放什么。

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

    堆 存放对象实例,几乎所有的对象实例以及数组都要在这里分配内存。

    虚拟机栈 线程私有。每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息

    本地方法栈 虚拟机用到的Native方法服务

    程序计数器 它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器。

  2. 堆里面的分区:Eden,survival from to,老年代,各自的特点。

  3. 对象创建方法,对象的内存分配,对象的访问定位。

    创建:new->检查这个指令参数是否能在常量池中定位到一个类的引用符号->判断这个类是否被加载、解析、初始化过->加载检查通过后,分配内存(指针碰撞,空闲列表)->对分配内存空间的动作进行同步处理(CAS配上失败重试、TLAB)->虚拟机需要将分配到的内存空间都初始化为零值->对对象进行必要的设置

    内存分配:对象头(header)、实例数据(Instance Data)、对其填充(Padding)

    对象访问: 句柄 直接访问;如果使用句柄访问的话,Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据的具体各自的地址信息。

  4. GC的两种判定方法:引用计数与引用链。

    对象死了么:引用计数算法;可达性分析算法(gc root)
    java GC ROOTS的对象包含以下几种
    虚拟机栈中引用的对象
    方法区中类静态属性引用的对象
    方法区中常量引用的对象
    本地方法栈种JNI(native方法)引用的对象

  5. GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?

    标记清楚:分为标记和清除两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。该算法的缺点是效率不高并且会产生不连续的内存碎片。

    把内存空间划为两个区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。优点:实现简单,运行高效。缺点:会浪费一定的内存。一般新生代采用这种算法

    标记阶段与标记清除算法一样。但后续并不是直接对可回收的对象进行清理,而是让所有存活对象都想一端移动,然后清理。优点是不会造成内存碎片

    新生代:复制算法 死得多 活的少
    老年代:标记整理 活得多

  6. GC收集器有哪些?CMS收集器与G1收集器的特点。

    JVM中的垃圾收集一般都采用“分代收集”,不同的堆内存区域采用不同的收集算法,主要目的就是为了增加吞吐量或降低停顿时间。

    • Serial收集器:新生代收集器,使用复制算法,使用一个线程进行GC,串行,其它工作线程暂停。
    • ParNew收集器:新生代收集器,使用复制算法,Serial收集器的多线程版,用多个线程进行GC,并行,其它工作线程暂停。使用-XX:+UseParNewGC开关来控制使用ParNew+Serial Old收集器组合收集内存;使用-XX:ParallelGCThreads来设置执行内存回收的线程数。
    • Parallel Scavenge 收集器:吞吐量优先的垃圾回收器,作用在新生代,使用复制算法,关注CPU吞吐量,即运行用户代码的时间/总时间。使用-XX:+UseParallelGC开关控制使用Parallel Scavenge+Serial Old收集器组合回收垃圾。
    • Serial Old收集器:老年代收集器,单线程收集器,串行,使用标记整理算法,使用单线程进行GC,其它工作线程暂停。
    • Parallel Old收集器:吞吐量优先的垃圾回收器,作用在老年代,多线程,并行,多线程机制与Parallel Scavenge差不错,使用标记整理算法,在Parallel Old执行时,仍然需要暂停其它线程。
    • CMS(Concurrent Mark Sweep)收集器:老年代收集器,致力于获取最短回收停顿时间(即缩短垃圾回收的时间),使用标记清除算法,多线程,优点是并发收集(用户线程可以和GC线程同时工作),停顿小。使用-XX:+UseConcMarkSweepGC进行ParNew+CMS+Serial Old进行内存回收,优先使用ParNew+CMS(原因见Full GC和并发垃圾回收一节),当用户线程内存不足时,采用备用方案Serial Old收集。
    • GI收集器:cms的替代? 并行于并发 分代收集 空间整合 可预测的停顿
  7. Minor GC与Full GC分别在什么时候发生?

    • 为了分代垃圾回收,Java堆内存分为3代:新生代,老年代和永久代。
    • 新的对象实例会优先分配在新生代,在经历几次Minor GC后(默认15次),还存活的会被移至老年代(某些大对象会直接在老年代分配)。
    • 永久代是否执行GC,取决于采用的JVM。
    • Minor GC发生在新生代,当Eden区没有足够空间时,会发起一次Minor GC,将Eden区中的存活对象移至Survivor区。Major GC发生在老年代,当升到老年代的对象大于老年代剩余空间时会发生Major GC。
    • 发生Major GC时用户线程会暂停,会降低系统性能和吞吐量。
  8. 几种常用的内存调试工具:jmap、jstack、jconsole。

    • jps:进程状态工具
    • jmap:生成堆存储快照
    • jstack:对战跟踪工具
    • jconsole:一个可视化java见识和管理控制台
  9. 类加载的五个过程:加载、验证、准备、解析、初始化。

    1.装载:

    • (1).找到该类型的class文件,产生一个该类型的class文件二进制数据流(ClassLoader需要实现的loadClassData()方法)
    • (2).解析该二进制数据流为方法区内的数据结构
    • (3).创建一个该类型的java.lang.Class实例
    • 在加载器的相关代码中可以看到,最终通过defineClass()创建一个Java类型对象(Class对象)。

    2.验证:
    class文件校验器需要四趟独立的扫描来完成验证工作,其中:

    第一趟扫描在装载时进行,会对class文件进行结构检查,如

    (1).对魔数进行检查,以判断该文件是否是一个正常的class文件
    (2).对主次版本号进行检查,以判断class文件是否与java虚拟机兼容。
    (3).对class文件的长度和类型进行检查,避免class文件部分缺失或被附加内容。

    第二趟扫描在连接过程中进行,会对类型数据进行语义检查,主要检查各个类的二进制兼容性(主要是查看超类和子类的关系)和类本身是否符合特定的语义条件

    (1).final类不能拥有子类
    (2).final方法不能被重写(覆盖)
    (3).子类和超类之间没有不兼容的方法声明
    (4).检查常量池入口类型是否一致(如CONSTANT_Class常量池的内容是否指向一个CONSTANT_Utf8字符串常量池)
    (5).检查常量池的所有特殊字符串,以确定它们是否是其所属类型的实例,以及是否符合特定的上下文无关语法、格式

    第三趟扫描为字节码验证,其验证内容和实现较为复杂,主要检验字节码是否可以被java虚拟机安全地执行。

    第四趟扫描在解析过程中进行,为对符号引用的验证。在动态连接过程中,通过保存在常量池的符号引用查找被引用的类、接口、字段、方法时,在把符号引用替换成直接引用时,首先需要确认查找的元素真正存在,然后需要检查访问权限、查找的元素是否是静态类成员而非实例成员。

    3.准备:

    为类变量分配内存、设置默认初始值(内存设置初始值,而非对类变量真正地进行初始化,即类中声明int i = 5,但实际上这里是分配内存并设置初始值为0)

    4.解析:

    在类的常量池中寻找类、接口、字段、方法的符号引用,将这些符号引用替换成直接引用

    5.初始化

    对类变量赋予指定的初始值(这个时候int i = 5就必须赋予i以初值5)。这个初始值的给定方式有两种,一种是通过类变量的初始化语句,一种是静态初始化语句。而这些初始化语句都将被Java编译器一起放在方法中。
    如前面所述,一个类的初始化需要初始化其直接超类,并递归初始化其祖先类,初始化是通过调用类的初始化方法完成的。此外,对于接口,并不需要初始化其父接口,而只需要执行该接口的接口初始化方法就可以了。

  10. 双亲委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。

启动类加载器Bootstrap ClassLoader javahome/lib

扩展类加载器Extension ClassLoader /lib/ext

应用程序类加载器ApplicationClassLoader 用户类路径

自定义类加载器

  1. 分派:静态分派与动态分派。

JVM过去过来就问了这么些问题,没怎么变,内存模型和GC算法这块问得比较多,可以在网上多找几篇博客来看看。
推荐书籍:《深入理解java虚拟机》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值