JVM学习总结六:补充面试题总结

六、补充面试题总结

1.JVM调优

1.调优参数
  • -Xms:设置初始堆大小;
  • -Xmx:设置最大堆大小;
2.设置新生代和老年代的比例

-XX:NewRatio:设置年轻代和老年代的比例;

3.设置伊甸园区和幸存者区的比例

-XX:SurvivorRatio=n;

4.设置永久代/元空间的大小
  • -XX:permSize;-XX:permMax;
  • -XX:metaSpaceSize;-XX:metaSpaceMax;
5.设置垃圾回收器
  • -XX:useG1GC;
  • -XX:useCMSGC;
6.打印相关日志
  • -XX:+printGC:打印垃圾回收
  • -XX:+printGCDetails:打印垃圾回收细节信息;
2.调优目的

减少GC的频次和Full GC的次数

3.调优过程
  1. 首选需要监控GC的状态,查看当前的堆内存快照及gc日志,根据实际的各区域划分和GC执行时间,判断是否需要优化。
  2. 生成堆的dump文件
  3. 分析dump文件
  4. 可以通过eclipse的工具Memory Analyzer
  5. 分析结果,判断是否需要优化
  6. 调整GC的类型和内存分配
  7. -XX:use+垃圾回收器+GC;
  8. 不断分析和调整参数

2.OOM及其解决?

OOM场景有哪些?
1. java堆内存溢出

原因:堆内存设置小或者内存泄露问题

解决:对于内存泄露的话,可以使用内存监控查找程序中的内存泄露的地方 加以更正;

对于堆内存设置问题,可以通过-Xms或者-Xmx来进行设置;

2.方法区溢出

原因:出现大量的Class或者jsp页面,过多的常量等会导致方法区溢出;

解决:可以通过设置方法区的大小来调节

-XX:Permsize;-XX:MaxPermSize设置永久代的大小;

-XX:metaSpaceSize;-XX:MaxmetaSpace设置元空间的大小;

OOM的解决方法
  1. 首先采用内存映像分析工具如(MAT)对dump出来的堆转储快照进行分析,确认内存中的对象是否是必要的,查明到底是内存泄露(GC无法回收的对象,如未在close()方法释放的连接,以及单列模式下存在外部引用)还是内存溢出.
  2. 如果是内存泄露,可进一步通过工具查看泄露对象到GC Roots的引用链,准确定位到泄漏代码的位置;
  3. 如果不存在泄漏的话,分析是堆内存溢出还是方法区溢出;
  4. 如果是堆内存溢出,则适当调整堆的大小:通过-Xms或者-Xmx来进行设置;
  5. 如果是方法区溢出,适当调整方法区的大小:通过-XX:Permsize;-XX:MaxPermSize设置永久代的大小;-XX:metaSpaceSize;-XX:MaxmetaSpace设置元空间的大小

3.jdk1.7和jdk1.8比较?

1.字符串放在什么位置?

均放在堆空间的字符串常量池中;

2.默认的垃圾回收器?

是一样的,都是Parallel scavenge+parallel old垃圾回收器。jdk1.9之后是G1垃圾回收器。

4.Full GC与Minor GC

1.Full GC触发条件

Full GC定义:完整收集整个堆和方法区的垃圾

  1. 老年代内存被占满
  2. 永久代/元空间内存被占满;
  3. System.gc()时会显式调用Full GC
  4. 空间担保失败(当老年代的剩余空间小于等于S区的平均对象大小时,表示空间担保失败)
2.Minor GC触发条件

Minor GC定义:只发生在新生代的垃圾回收

当新生代的伊甸园区满了之后,就会触发Minor GC,回收整个年轻代的垃圾

Minor GC出发结果:当进行Minor GC时,会产生STW,存活的对象移动到幸存者区

5.Full GC与Minor GC

1.CMS和G1垃圾回收器比较
1.CMS垃圾回收器(主打低延时)
1.介绍

是hotspot虚拟机第一款并发的垃圾回收器,垃圾回收线程和用户线程可以并发执行,不需要STW,因此能够提升用户体验,降低延迟性,适合于频繁交互的场景。

2.执行过程

在这里插入图片描述

  1. 初始标记:仅仅只是标记出GC Roots能够直接关联到的对象,存在STW机制(很短暂的STW)。
  2. 并发标记:从GC Root直接关联到的对象开始,遍历整个对象图的过程,该阶段不需要停顿用户线程。
  3. 重新标记:修正并发标记阶段,因用户线程运行而导致标记产生变动的那一部分对象的标记记录,存在STW机制,会产生浮动垃圾
  4. 并发清除:清除标记为已经死亡的对象,释放内存空间。
3.优缺点
  1. 优点:并发收集;低延迟;

  2. 缺点:

    1. 会产生内存碎片,当老年代需要为大对象分配内存时,不得不提前触发Full GC;
    2. 无法处理"浮动垃圾",可能导致"并发失败",从而引发Full GC
    3. 对CPU资源比较敏感:CMS默认的垃圾回收线程数为(处理器核心数+3)/4,对于处理器核心数比较少的情况,垃圾回收线程就占比较大,影响执行速度。

    浮动垃圾:因为在并发清理阶段,垃圾收集线程和用户线程在并发执行,用户线程运行过程中,会产生新的垃圾,而这部分垃圾是发生在标记阶段之后的,所以只能等到下一次GC时,才能够进行回收,这时候需要预留出一定的内存空间,在下图中,a=null后b和c就是垃圾了但是在这一轮垃圾回收中判定不是垃圾,但是会在下次垃圾回收中回收。

在这里插入图片描述

4.使用场景

主打低延时,用于频繁交互的场景

2.G1垃圾回收器
1.概述
  1. 目标是在停顿时间可控的情况下,尽可能提高吞吐量的垃圾回收器
  2. 将整个堆内存分为多个region区域,跟踪每个Region区的垃圾堆积的价值大小,然后后台维护一个优先级列表,每次根据允许的收集时间,优先回收价值大的region
  3. 基于复制算法和标记整理的算法的并行垃圾回收器,为jdk1.9默认的垃圾回收器
2.G1的回收过程
  1. 初始标记:只标记GC Roots直接关联到的对象,此过程需要STW(短暂STW)
  2. 并发标记:从GC Root关联到的对象开始,递归遍历整个对象图,此时垃圾收集线程和用户线程并发执行
  3. 最终标记(类似于CMS重新标记):由于在并发标记阶段,用户线程在执行,需要对标记结果进行修正,此时需要STW.
  4. 筛选回收:根据用户设置停顿时间,采用复制算法进行清理(将决定回收的Region中的存活对象复制到空的Region中,然后清空旧的Region空间),此过程需要STW

在这里插入图片描述

3.优缺点

优点:

  1. 并发与并行

并行性:在G1垃圾回收期间,可以有多条垃圾回收线程同时进行回收,有效利用多核计算能力。

并发性:在G1并发标记阶段,允许垃圾收集线程和用户线程并发执行。

  1. 分代收集

G1同时兼顾了年轻代和老年代。因为G1垃圾收集器将堆空间分为不同的Region区,这些区域包含了逻辑上的新生代和老年代。

  1. 不存在内存碎片化问题

因为G1垃圾回收器以Region为基本内存回收单元,Region之间采用复制算法,但是从整体上来说,是采用标记-整理算法,因此可以避免内存碎片问题。

  1. 可预测的停顿时间模型(软实时)

使使用者明确在一个长度为M的时间片段内,用于垃圾回收的时间不超过N

主要是因为G1跟踪各个Region的垃圾堆积价值的大小,然后后台维护一个优先级列表,在有限的时间内,优先收集价值大的Region

缺点(不适合小内存应用)

由于垃圾收集产生的内存占用相对大,小内存应用上性能不如CMS。

3.应用场景

面向服务端的垃圾收集器,适用于配备多核CPU和大容量内存的机器。

2.其他垃圾回收器
1.serial及serial old垃圾回收器(串行回收)
1.Serial垃圾回收器

采用复制算法串行收集Stop The World的方式来对新生代进行垃圾收集。是HotSpot虚拟机在客户端模式下默认的新生代垃圾回收器

2.Serial Old垃圾回收器

采用标记-整理算法串行收集Stop The World的方式来对老年代进行垃圾收集。是HotSpot虚拟机在客户端模式下默认的老年代垃圾回收器

3.回收过程

在这里插入图片描述

4.回收优势

因为是单线程,因此没有线程交换的开销,相对于其他垃圾收集器的单线程相比,简单而高效。

5.参数设置
-XX:useSerialGC/useSerialOldGC设置
2.ParNew垃圾回收器(并行回收)
1.回收模式

采用复制算法并行回收和STW的机制进行垃圾回收,是JVM在服务端下的默认新生代垃圾回收器

2.组合搭配

可以和Serial Old搭配使用(JDK9中移除);可以和CMS配合使用(JDK14中删除)

在这里插入图片描述

3.优势

对于新生代,回收次数频繁,因此采用并行方式更加高效。

4.参数设置
-XX:useParNewGC
3.Parallel垃圾回收器(吞吐量优先)
1.Parallel Scavenge垃圾回收器(新生代)

采用复制算法并行回收STW的机制进行垃圾收集。

2.Parallel Scavenge垃圾回收器与ParNew的区别

Parallel Scavenge的目标是达到一个可控吞吐量,而且具备自适应调节策略。

3.Parallel Old垃圾回收器(老年代)

采用标记-整理并行回收STW的机制进行垃圾收集,在JDK8中,默认Parallel Scavenge+Parallel Old为垃圾回收器。

在这里插入图片描述

4.适用场景

高吞吐量则可以高效的利用cpu的时间,来快速实现计算。主要适合在后台运行而不需要太多交互的任务

3.为什么要分代?

因为java对象的生命周期是不同的,大部分对象的声明周期是比较短暂的,少部分对象的声明周期是比较长的,甚至是伴随着JVM的消亡而消亡,通过分为新生代和老年代两种内存区域,将声明周期短暂的对象放在新生代,将声明周期较长的对象放在老年代,在进行垃圾回收的时候,能够提高效率;如果不采用分代的话,在进行垃圾回收的时候,需要遍历整个堆空间,造成STW时间过长,影响用户体验

6.Full GC与Minor GC

1. 类加载子系统

详见第二章

2.运行时数据区
1.程序计数器

作用:记录虚拟机字节码指令的下一条地址,当一个线程再次获得CPU执行权的时候,能够保证下一条执行从哪儿继续;

2.虚拟机栈
1.作用

主管java程序的运行,虚拟机栈中存储着栈帧,对应着一个一个执行的方法,当方法执行的时候,会进行压栈操作,方法执行完后进行弹栈。

2.组成
  1. 局部变量表
    1. 存储方法的参数及局部变量,如果是基本数据类型,则会存储变量值,如果是引用数据类型的话,则存储的是引用地址值。
  2. 操作数栈
    1. 临时存储变量,作为变量计算的中间结果的临时存储区域
  3. 动态链接
    1. 将虚拟机栈中的符号引用转为方法区中的方法的直接引用;
  4. 方法返回地址
    1. 存储方法的返回地址,方便调用者能够获取到方法的返回值。
3.与本地方法栈的区别

虚拟机栈负责java程序的执行;本地方法栈作用类似于虚拟机栈,负责本地方法的执行,本地方法指的的用C/C++编写的程序,作为方法的扩展库;hotSpot虚拟机将两者合二为一。

3.堆

作用:绝大多数的创建的对象将会存储在堆中;jdk1.7之后静态变量及字符串常量存储在堆空间中

4.方法区

作用:存储类信息,域信息,方法信息,常量,即时编译器的代码缓存也就是热代码(JIT),jdk1.6及之前存储静态变量。

5.本地方法栈

作用:负责本地方法的运行,本地方法指的是用C/C++编写的程序,作为方法的扩展库

3.执行引擎

详情见执行引擎

本地方法接口/本地方法库

7.JVM类加载过程

  1. 加载
    1. 通过一个类的全限定名来获取此类的二进制字节流;
    2. 将该二进制字节流所代表的的静态存储结构转化为方法区的运行时数据结构
    3. 在内存中生成一个代表该类的java.lang.Class对象,作为方法区这个类的数据访问入口。
  2. 连接
    1. 验证:确保Class文件的字节流(二进制)中包含的信息符合规范,保证这些信息被当做代码运行后不会对虚拟机造成危害。分为:文件格式验证元数据验证字节码验证符号引用验证四个方面。
    2. 准备:正式为类的静态变量分配内存并设置初始值(隐式初始化->相当于赋默认值)。
    3. 解析:Java虚拟机将常量池中的符号引用替换为直接引用。分为:类或接口的解析、字段解析及方法解析、接口方法解析
  3. 初始化:在准备阶段,静态变量已经赋过一次系统要求的初始零值,而在初始化阶段,会根据程序员通过程序编码指定的主观计划去初始化静态变量和其他资源。

8.JVM类加载过程

类加载器在加载类时采用的 loadClass() 方法使用了Synchronized关键字进行修饰。

9.双亲委派机制

1.定义

当一个类需要加载时,负责加载此类的加载器不会立即对其进行加载,而是递归的委托给其父类加载,父类收到这个加载任务后也会向上进行委托,直到引导类加载器,如果引导类加载器能够加载此类,则会进行加载,如果无法实现加载此类,则会返回给其子类进行加载。

2.好处
  1. 这样做可以有效地防止类被重复加载
  2. 能够保护java的核心类库,放置核心的API被随意篡改
3.各个类加载器加载的类的文件名
1.引导类加载器

java的核心类库都是使用引导类加载器加载的,加载的文件存放在<JAVA_HOME> /lib文件夹中;

2.扩展类加载器

扩展类加载器负责加载<JAVA_HOME>/lib/ext目录中的jar文件

3.应用程序类加载器

应用程序类加载器加载的是用户类路径上的类库

10.垃圾回收算法

1.标记-清除算法
  1. 原理:当需要进行GC时,会停止整个程序(STW),然后整个GC过程分为标记阶段和清除阶段
    标记:从引用根对象开始遍历,标记所有被引用的对象,一般在对象头中记录为可达对象。
    清除:对堆内存进行从头到尾的遍历,如果发现某个对象的对象头没有被标记为可达对象,则进行回收

在这里插入图片描述

  1. 优点:最基本的垃圾回收算法

  2. 缺点

    1. 因为需要遍历,所以执行效率不高;
    2. 在进行GC时,需要STW,效率不高的话,会影响用户体验;
    3. 产生内存碎片化问题
2.复制算法(适合在新生代)
  1. 原理:将内存空间分为大小相等的两块,每次只使用其中的一块,垃圾收集时,将正在使用的内存中的存活的对象复制到另一块内存中,然后将正在使用的内存清空。交换两个内存的角色,完成垃圾回收。在堆中新生代分为eden,s0,s1,其中s0,s1就是用的复制算法

在这里插入图片描述

  1. 优点

    1. 执行效率高,省去了清除中的遍历问题
    2. 解决了内存碎片化的问题
  2. 缺点

    1. 空间浪费较明显,始终有一块内存无法使用;
    2. 对于G1这种分成很多region的垃圾回收器来说,复制意味着需要维持region之间对象的引用关系,空间和时间的开销比较大。
  3. 适合场景

    1. 比较适合于垃圾对象较多,存活对象较少的区域,如新生代中的Survivor0区和Survivor1区。不适合老年代中垃圾回收。

在这里插入图片描述

3.标记-整理(压缩)
  1. 原理
    1. 第一阶段和标记-清除算法的标记阶段一样,从根结点开始标记所有被引用的对象
    2. 第二阶段将所有存活的对象压缩到内存的一端,按顺序排放,然后清除边界以外的内存空间

在这里插入图片描述

  1. 优点

    1. 解决了标记-清除内存碎片化的问题
    2. 解决了标记-复制空间浪费一半的问题
  2. 缺点

    1. 整理过程中需要移动对象,如果对象被其他对象所引用,则需要不断调整引用的地址
    2. 效率相对另外两种算法较低;
  3. 适用场景:适合于老年代中的垃圾收集

4.三种垃圾回收算法对比
算法标记-清除复制标记-压缩(整理)
执行效率中等最快最慢
空间开销少(存在内存碎片化大(浪费一半空间)小(不会产生内存碎片化
移动对象

11.如何选择垃圾回收器

  1. 优先调整堆的大小,让jvm能够适应
  2. 如果是内存比较小,选择serial+serial Old垃圾回收器
  3. 如果是单核,没有停顿时间要求,选择serial+serial Old垃圾回收器
  4. 如果是多核CPU,需要高的吞吐量,选择parallel scanvenge+parallel Old垃圾回收器;
  5. 如果是多核cpu,低停顿时间
  6. 如果是jdk14以前,可以选用CMS+ParNew;jdk14后,G1垃圾回收器

12.对象的内存分配策略

  1. 优先分配到新生代(先分配到Eden区,再经过GC回收后进入S区)
  2. 大对象直接分配在老年代
  3. 长期存活的对象(新生代中的S区的对象年龄达到了设定的阈值,jdk1.8经过15此垃圾回收进入老年代,G1则经过6此进入老年代)分配到老年代
  4. 动态判断对象年龄:如果相同年龄的对象所占的空间大于等于S区的一半,则大于等于该年龄的对象则会被分配到老年代中。

13.垃圾判定方法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值