JVM面试题
JVM的内存模型,主要分为堆、方法区、栈、程序计数器、本地方法栈;
类的加载流程是加载 --> 验证 --> 准备 --> 解析 --> 初始化;
对象的创建流程是:类加载检查 --> 加载类 --> 内存分配 --> 初始化 --> 设置对象头 --> 执行 <init> 方法;
内存分配流程:先判断栈帧(逃逸分析),然后判断老年代(大对象),再是堆内存空间的年轻代(TLAB);
说一下你对JVM的内存模型的理解
JVM的内存模型里,主要分为堆、方法区、栈、程序计数器、本地方法栈。
其中堆和方法区是所有线程共享的,栈、程序计数器、本地方法栈是各线程私有的。
本地方法栈是C++实现方法使用的专属空间。(一笔带过即可)
程序计数器是用来记录当前线程执行到的代码行,防止在本线程失去CPU调度权限后,出现执行任务进度丢失的问题,让该线程在下次获取到CPU资源后,可以继续从上次中止的地方继续往下执行。
方法区是也叫元空间,由 -XX:MetaSpaceSize参数控制大小,用于存储类元数据信息类名、类的类型、类的修饰符等、方法的方法名、方法的返回类型、成员变量名、成员变量类型等等、常量与常量值、静态变量的引用。
栈,是每个线程运行时会分配的内存空间,用Xss参数控制一个线程分配栈内存大小,分配给线程的栈内存空间里,还会再继续往下进行分配,一个方法会被分配一个栈帧,一个栈帧里又区分为局部变量表、操作数栈、动态链接、方法出口,局部变量表用来存放作用域仅在本方法里的变量,操作数栈用来临时存储需要进行计算的数据,动态链接用来存放符号引用对应的直接引用,方法出口用于记录本方法执行完毕后,继续从哪一行代码继续执行。
堆,是JVM里占用最大的内存空间,使用-Xms和-Xmx参数控制大小,像User user = new User(),这样new出来的对象,就是存放在堆里面的,然后一般在栈帧里局部变量表里的变量名user,通过内存地址指向堆空间里的这个对象。
(关于堆,可扩展回答堆里分为新生代、老年代等,以及GC,各种垃圾收集器)
更多详细内容《 JVM内存模型深度剖析与优化 》
说一下类的加载流程
类的加载流程是加载-->验证-->准备-->解析-->初始化
加载,是将.class文件二进制字节流加载到内存中,也就是元空间MateSpace,元空间会存储这个类的各种元数据信息,包括对象头、成员变量等。
验证,是校验加载类的语法、规范等,确保类符合JVM的规范。
准备,给变量分配内存,并设置默认初始值,是默认的0或空字符串,不是程序中的初始值。
解析,将常量池里的符号引用,替换为直接引用,就是调用时,替换为了内存地址。
初始化,就是执行statisc {} 等静态代码块和构造方法,以及给变量赋上代码里设定的值。
对象的创建流程是什么
对象的创建流程是: 类加载检查-->加载类-->内存分配-->初始化-->设置对象头-->执行 <init> 方法
类加载检查,就是检查创建对象的类以及其成员属性类型,是否有还未加载。
加载类,就是将类加载检查时检查到为加载的类进行加载,将其加载到内存里,在方法区。
内存分配,在堆内存空间里划分一块空间给创建的对象使用。
初始化,给分配的内存空间都赋0值、"" 空字符串值,目的是为了让这个对象的成员属性在代码中不赋值时也可以使用。
设置对象头,主要是设置哈希码、分代年龄、锁状态、执行类元信息的指针等信息。
执行 init 方法,就是按照事先编写代码里的逻辑进行初始化,就是执行父类的构造方法、执行显式赋值(就是String a = "hello")、执行 {} 代码块、执行构造方法。
对象的内存分配流程是什么
先判断栈帧(逃逸分析),然后判断老年代(大对象),再是堆内存空间的年轻代(TLAB)。
new一个对象时,需要在JVM的内存空间里给他分一块空间。
先通过逃逸分析判断是否对象是否有被方法以外的地方使用,如果没有,就表明他的作用域仅局限于本方法,生命同本方法一样,方法结束时就可以直接销毁。
这种对象就可以直接分配到方法的栈帧空间里,可以有效减少gc压力,当然前提是栈帧的内存空间足够,如果栈帧的内存空间不足以存放这个对象,也会使用标量替换方法,将对象分解为若干个被这个方法使用的成员变量存入栈帧、寄存器。
如果对象没有被分配到栈帧,就会继续判断其是否是大对象,如果是大对象,则直接分配到老年代,大对象的大小由-XX:PretenureSizeThreshold参数控制,但是只有Serial和ParNew垃圾回收器下才有效。
大对象直接分配到老年代的目的是,减少其在年轻代、survivor区之间复制来复制去,积攒分代年龄,而占用资源,且效率低。
如果不符合大对象标准,就是普通的内存分配流程,会被分配到堆内存空间的年轻代(TLAB分配,每个线程在年轻代里都会有一块私有的内存区域,这样在分配空间时就不需要加锁,效率较高),然后gc后再到survivor,最后再到老年代。
详细内容《 JVM对象创建与内存分配机制深度剖析 》
- GC的回收算法有哪些
