0
点赞
收藏
分享

微信扫一扫

第一章--JVM面试题

善解人意的娇娇 2023-05-31 阅读 47

1. 导读部分

写在开始 : 本文是学习 [黑马程序员] JVM 面试专题 的学后记录, 仅仅用作个人复习准备面试用。
附学习地址 : https://www.bilibili.com/video/BV1yT411H7YK?p=116&vd_source=08ac522c6603c56e243d5e129a309a60
image.png
image.png
image.png
image.png

2. JVM 组成

2.1 程序计数器

个人回答 : 程序计数器是运行时数据区的一部分,用来指向执行的指令的位置,唯一不会发生OOM的地方;

image.png

2.2 堆

个人回答 : 堆一般是运行时数据区空间最大的地方,存放的对象和数组;堆是线程共享的,也是垃圾回收的主要对象;堆分为新生代和老年代,新生代又分为eden区和s from 和 s to区,一般比例是8:1:1;

  • 年轻代分为三部分,Eden区和两个大小严格相同的 Survivor 区
  • 老年代主要保存生命周期长的对象,一般是一些老对象

image.png
image.png

2.3. 方法区

个人回答 : 方法区也是线程共享的,7及之前是永久代,8及之后是元空间,

image.png
:::info

:::
image.png
image.png

2.4. 直接内存

个人回答 : 没听过

image.png
image.png

2.5 虚拟机栈

个人回答 ; 虚拟机栈也是运行时数据区一部分,每个线程私有,生命周期随着线程的产生和销毁而变化,当内存空间不够会抛出 stackoverflow 异常,也可能有情况抛出 OOM 异常,存储的是方法出口,局部变量等,栈内存按照先进后出的顺序执行;
:::info

:::

2.6 垃圾回收是否涉及栈内存

个人回答 : 垃圾回收主要针对堆内存,栈是方法执行完毕弹栈释放,内存自动释放

2.7 栈内存分配越大越好吗

个人回答 : 不一定
:::info

:::

2.8 方法内的局部变量是否线程安全

个人回答 : 不一定
:::info

:::
image.png

2.9 栈内存溢出的情况

个人回答 ; 栈帧过大

// 1 栈帧过多导致栈内存溢出,典型问题 : 递归调用
// 2 栈帧过大导致栈内存溢出

public static void m1(){
    m1();  // 抛出 java.lang.StackOverflowError异常
}

栈堆的区别是

个人回答见下表:

区别
大小一般是1024K随对象的大小而定,一般大于栈
私有每个线程私有共享区域
生命周期随方法调用一样对象创建存在,垃圾回收可能消失
异常类型两种 SOF OOM只有 OOM
存啥存局部变量和返回地址等对象和数组等
垃圾回收
物理地址连续,性能快不连续,性能慢

3. 类加载器

3.1 类加载器是什么?有哪些

个人回答 : 类加载器就是对类的信息进行加载,有引导类加载器,扩展类加载器,系统应用类加载器以及自定义类加载器等几种
:::info

:::

3.2 双亲委派模型

个人回答 : 类的加载优先找父类加载器进行,首先是引导类,其次是扩展类,然后是系统应用类加载器,最后是自定义的,为了保证安全,核心类库不被篡改;
:::info

:::

3.3 JVM为什么用双亲委派机制

:::info

:::
image.png

3.4 类装载执行过程

个人回答 : 准备 -> 连接 -> 初始化 太长记不清楚了,其中连接分为验证解析引用
:::info

:::

image.png

4. 垃圾回收

强引用,软引用,弱引用,虚引用

个人回答 : 强不会被回收,软,当内存不够时会回收,弱,内存无论是否够都回收,虚
:::info

:::
:::info

:::

static class Entry extends Weakreference<ThreadLocal<?>>{
    Object value;

    Entry(ThreadLocal<?> k,Object v){
        super(k);
        value = v; // 强引用,不会被回收
    }
}

判断对象可被垃圾器回收

个人回答 : 引用计数 可达性分析
:::info

:::
:::info
引用计数:
一个对象被引用一次,在当前对象头上递增一次引用次数,如果对象引用次数0,则可回收;
当对象出现了循环引用,则失效;引发内存泄漏;
可达性分析:

:::

JVM垃圾回收算法

个人回答 : 标记清除,标记整理(针对老年代),复制算法(新生代常用)
:::info

:::

分代回收

个人回答 : 主要针对不同的内存区域采用不同的垃圾回收方式,垃圾回收器
image.png
image.png
image.png
:::info

  1. 堆区域划分
    1. 堆被分2份:新生代和老年代(1:2)
    2. 新生代内部分为三部分 Eden区 幸存者区 survivor(from和to) 8:1:1
  2. 对象分代回收策略
    1. 新建对象,去Eden
    2. 当 Eden内存不足,标记Eden和from的存活对象
    3. 复制算法到 to区,完毕后 Eden和from 内存释放
    4. 一段时间Eden内存又不足,标记Eden区to区存活对象,复制到 from区
    5. 幸存区对象熬过15次回收,晋升到老年代(大对象提前晋升)

MinorGC 新生代垃圾回收,暂停时间短 (STW)
Mixed GC 新生代和老年代部分区域垃圾回收 G1特有
FullGC 新生代老年代完整垃圾回收,暂停时间长,尽力避免
:::

G1 垃圾回收器

个人回答 :

  • 应用于新生代和老年代,9以后默认使用 G1
  • 划分多个区域,每个区域可充当 eden survivor old humongous(专为大对象准备)
  • 采用复制算法
  • 响应时间和吞吐量兼顾
  • 分三个阶段 新生代回收(stw)、并发标记(重新标记 stw)、混合收集
  • 如果并发失败(回收赶不上新建对象速度)触发Full GC

哪些垃圾回收器

串行垃圾收集器
Serial GC | Serial Old GC
并行垃圾收集器
Parallel Old GC | parNew GC
CMS(并发)垃圾收集器 作用在老年代
image.png

5. JVM 实战

JVM 调优参数哪里设置

:::

JVM 调优参数有哪些

堆空间大小 Xms堆初始化大小 Xmx堆最大大小

  • 最大大小默认值物理内存25%,初始大小1/64;
  • 堆太小,导致频繁的垃圾回收,stw,
  • 堆内存打肯定好的,存在风险,假如 FullGC 扫描整个堆空间,stw时间长
  • 最终: 尽量大,也需考虑当前计算机其他程序内存使用情况;

虚拟机栈的设置

  • 每个线程默认1M,存放栈帧,调用参数,局部变量等,一般256K就够用 -Xss128K
  • 通常减少线程的堆栈,可产生更多线程,实际受限于操作系统;

Eden和Survivor大小比例
年轻代晋升老年代阈值
**设置垃圾回收器 **

JVM 调优工具

image.png
image.png

内存泄漏排查思路

image.png
image.png
image.png
内存泄漏通常指堆内存,一些大对象不被回收的情况

  1. 通过 jmap 或设置 jvm 参数获取堆内存快照 dump
  2. 通过工具, VisualVM 分析 dump 文件,可加载离线的 dump 文件
  3. 通过查看堆信息情况,大概定位内存溢出的代码位置
  4. 找到对应代码,通过阅读上下文,进行修复即可

CPU 飙高排查方案和思路

image.png

  1. 找线程信息

ps H -eo pid,tid,%cpu | grep 40940
分析得到进程40940里 4.950占用cpu 较高

  1. 根据线程id 找有问题的线程 ,进一步定位到问题代码的源码行号

jstack 40940
40940是进程id,40955是线程id
十进制转十六进制
printf “%x\n” 4.955

:::info

  1. top命令查看cpu占用情况
  2. top命令查看后,可查哪个进程占用cpu较高
  3. ps命令查看进程的线程信息
  4. jstack命令查进程的哪些线程出现问题,最终定位问题;
    :::
举报

相关推荐

0 条评论