JVM面试题总结

类加载过程

https://cloud.tencent.com/developer/article/1749366

加载——链接(验证、准备、解析)——初始化——卸载(程序结束或异常终止)

加载(3件事):

  1. 通过全类名获取该class文件,以二进制流的形式读入内存
  2. 将字节流所代表的静态存储结构转化为方法区的运行时数据结构
  3. 在内存中国生产一个类的class对象,最为方法区这个类的各种数据入口

验证:验证文件格式、语义、语法、符号引用是否有错误

准备:静态变量在方法区分配内存并赋初值

解析:将符号引用转化为直接引用

初始化:对类变量赋值和初始化操作,如果有父类则优先初始化父类

java对象创建过程

  1. 类加载检查
    1. 先判断这个类是否被加载过,如果没有先执行类的加载过程
  2. 分配内存
    1. 对象的内存大小在类加载完成的时候就可以确定下来
    2. 内存分配方式有指针碰撞和空闲列表
    3. 内存分配并发问题
      1. 创建对象是频繁的,需要保证线程安全问题
        1. CAS失败重试
        2. TLAB,为每个线程分配一个tlab
  3. 初始化零值
    1. 为属性、代码块、构造器等所有的属性赋予默认值,保证对象实例字段在不赋值的情况下可以使用
  4. 设置对象头
    1. 将对象的类信息、hashcode和对象的gc信息、锁信息存储到对象头中
  5. 执行init方法
    1. 对属性赋值
  6. 完成

为什么要打破双亲委派机制

https://www.cnblogs.com/lyc88/articles/11431383.html

因为类加载器收到了加载范围的限制,在某些情况下父类加载器无法加载到所需要的文件,这时候就需要委托子类加载器去加载class文件。

JDBC的Driver接口定义在JDK中,其实现由各个数据库的服务商来提供,比如MySQL驱动包。DriverManager 类中要加载各个实现了Driver接口的类,然后进行管理,但是DriverManager位于 $JAVA_HOME中jre/lib/rt.jar 包,由BootStrap类加载器加载,而其Driver接口的实现类是位于服务商提供的 Jar 包,**根据类加载机制,当被装载的类引用了另外一个类的时候,虚拟机就会使用装载第一个类的类装载器装载被引用的类。**也就是说BootStrap类加载器还要去加载jar包中的Driver接口的实现类。我们知道,BootStrap类加载器默认只负责加载 $JAVA_HOME中jre/lib/rt.jar 里所有的class,所以需要由子类加载器去加载Driver实现,这就破坏了双亲委派模型。

jvm内存模型

线程私有:程序计数器、虚拟机栈、本地方法栈

线程共享:

  • 新生代、

  • 方法区

  • 直接内存(非运行时数据区)

jdk1.8前:有方法区,和堆放在一起(内存中的数据)

jdk1.8后:方法区改为元空间,数据放到直接内存中

常见的垃圾回收器有哪些

image-20200713094745366

  1. Serial收集器

    1. 单线程串行

    2. serial:复制算法,serial old:标记整理

    3. 一条垃圾收集线程,会产生大量的stw

      image-20200713100703799

  2. ParNew收集器

    1. 多线程并行,Serial的升级版

    2. ParNew复制算法,老年代(一般使用cms)标记整理

    3. 多条垃圾收集线程,在gc的时候会stw

    4. 除了Serial外,只有ParnewGC能与CMS收集器配合工作

      image-20200713102030127

  3. Parallel Scavenge

    1. 多线程并行,Serial的升级版
    2. 新生代复制算法,老年代标记整理
    3. 多条垃圾收集线程,在gc的时候会stw
    4. 和Parnew的主要区别为使用自适应调节策略,高吞吐量,主要适用于运算而不需要太多交互的地方,常在服务器中使用
    5. jdk1.8的默认

    image-20200713110359441

  4. CMS收集器

    1. 多线程并发
    2. jdk1.5的时候出现
    3. 主要为低延迟,适合页面交互
    4. 老年代标记清除算法

    image-20200713205154007

    主要分为四个阶段

    1. 初始标记
      1. 快速标记GCRoots能直接关联的对象
    2. 并发标记
      1. 耗时较长,但是是并发执行的,没有stw
      2. 从GCRoots对象开始遍历整个对象图的过程
    3. 重新标记
      1. 在并发标记的时候,工作线程和垃圾线程同时或交叉运行,为了修正并发标记出现的变动
      2. 耗时较长,但是远比并发标记的时间短
      3. 会产生stw
    4. 并发清除
      1. 此阶段清理删除,标记阶段死亡的对象,由于不需要移动存活对象,这个阶段也是并发的(这个也是为什么不使用标记整理的原因)

    缺点:

    1. 产生内存碎片,如果空间不足,在无法分配大对象的情况下,不得不提前触发FULLgc
    2. cms虽然不会导致用户停顿,但是因为占用了一部分线程导致程序变慢,总吞吐量降低
    3. 无法处理浮动垃圾,gc线程和用户线程交叉运行,可能在运行中出现垃圾,但是这个时候gc无法对垃圾记性回收,只能等到下一次
  5. G1收集器

    image-20200713215133839

    1. 在延迟可控的情况下获得尽可能高的吞吐量
    2. 全新的分区算法

空间整合:

cms:”标记-清除“算法、产生内存碎片,若干次gc后进行一次碎片整理

g1:划分为一个个的region,内存的回收是以Region为单位(一个大对象可以跨region存放)。region之间是复制算法,但是可以看做标记整理算法,可以避免内存碎片的产生

可预测的停顿时间模型:

这是G1相对于CMS的另一大优势,G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。

  • 由于分区的原因,G1可以只选取部分区域进行内存回收,这样缩小了回收的范围,因此对于全局停顿情况的发生也能得到较好的控制。
  • G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。
  • 相比于CMSGC,G1未必能做到CMS在最好情况下的延时停顿,但是最差情况要好很多。

相较于CMS,G1还不具备全方位、压倒性优势。比如在用户程序运行过程中,G1无论是为了垃圾收集产生的内存占用(Footprint)还是程序运行时的额外执行负载(overload)都要比CMS要高。

从经验上来说,在小内存应用上CMS的表现大概率会优于G1,而G1在大内存应用上则发挥其优势。平衡点在6-8GB之间。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值