Appearance
1.谁来负责将Class文件加载到内存?
类装载器;但类装载器只负责装在,是否可以执行由执行引擎决定。
2. .class文件存在内存哪个位置
方法区;存放的类信息包括:变量名、方法名、方法代码、访问权限等等
3.Class对象存储在哪里?一个类什么时候进入JVM?
堆;
- 虚拟机启动时,执行main()方法的时候
- new对象的时候
- 读取静态字段或静态方法的时候
4.如下代码输出的结果是什么?
java
public class Main {
static {
System.out.println("Main static");
}
public static void main(String[] args) {
System.out.println("Main main begin");
Son a = new Son();
System.out.println(Son.width);
Son b = new Son();
}
}
class Father {
static {
System.out.println("Father static");
}
}
class Son extends Father{
public static int width = 60;
static {
System.out.println("Son static");
width = 30;
}
public Son() {
System.out.println("Son Init");
}
}
点击显示答案
java
Main static // 执行Main的<clinit>方法
Main main begin
Father static // 执行Father的<clinit>方法
Son static // 执行Son的<clinit>方法
Son Init // 执行Son的<init>方法
30
Son Init // 执行Son的<init>方法
5.调用一个类的final字段会触发初始化吗?调用静态方法呢?聊一下什么是类的主动引用
- 只调用final字段不会触发类的初始化
- 调用静态方法,会先触发类的初始化
- 反射调用也会触发
- 先初始化父类,再初始化子类。
- 详见类的初始化顺序
6.你能想到哪些引用类但没有触发类的初始化的例子(被动引用)?
- 通过子类引用父类static变量,例如Son.count,count是父类的变量
- 定义数组类,例如
new Student[10]
- 只引用
static final
修饰的变量 - 详见类的初始化顺序
7.JVM中的程序计数器有什么用?
- 每个线程都有一个程序计数器
- 记录字节码指令地址
- 当多线程切换恢复时,通过程序计数器接着执行下一条指令
8.JVM的栈与堆分别存放什么,有什么区别?
- 栈
- 存放基本数据类型、局部变量;如果是对象,则只存放地址;
- 方法执行完毕(栈帧出栈)立即释放;
- 由于只存在单线程,其他线程无法访问;
- 堆
- 所有线程共享
- 用完后靠GC回收
- 堆内对象的变量都有默认值
9.什么是短命对象?什么是长命对象?
- 长命对象:一直被引用就是长命对象
- 短命对象:例如方法执行完毕就没人引用,即出栈后无引用
- 在JVM中,大部分都是短命对象;少数对象长期存活
10.什么是年轻代与老年代?
年轻代存储短命对象;老年代存储长命对象。
11.堆的内部结构是怎样的?
年轻代和老年代的内存占比是1:2
,年轻代还被划分如图所示的两个区域(Eden和Surivior)
12.压测理论分析:QPS=1000大概需要多少内存?
- 假设商品列表有10个字段,平均每个字段100字节,10*100≈1KB
- 访问一页是10条数据,每次访问会产生10KB
- 1000*10KM≈10MB,每秒大概需要10M
13.QPS=1000要保证YGC不能再一分钟内被触发,JVM参数该如何配置?
- 年轻代内存不足的时候(Eden和From区不够)触发YoungGC,即堆内存
- 1s=10M,那么一分钟10*60=600M
young:old=1:2=600:1200
,堆内存需要配置为1800M
14.Object对象在堆中以什么形式存储?
- 由4部分组成,MarkWord、class对象指针、数据内容和对其填充
- class对象指针指向方法区,方法区记录类的信息,如字段、方法、常量等
15.MarkWord是什么?记录了哪些东西
- MarkWord是对象头信息一部分,对象头包含MarkWord和class对象指针
- 记录锁状态、锁类型、锁状态、偏向锁信息
16.你MarkWord记录了锁的信息,记录的是什么锁?什么情况会产生锁?
- 无锁、匿名偏向锁、偏向锁、轻量级锁、重量级锁
- MarkWord记录锁的信息,没有数据访问时是无锁001
- 当有一个线程访问时,会产生匿名偏向锁101
17.那么匿名偏向锁和偏向锁的关系是什么?
- 线程第一次进入同步块,会记录线程ID,也就是使用同步代码块才会产生偏向锁
- 下一个线程进入代码块会判断是不是这个线程
- 如果不是,则尝试使用CAS替换线程ID,如果替换失败代表之前的线程还在,此时升级为轻量级锁
- 偏向锁的功能是在无竞争的情况下减少锁竞争的开销
18.什么时候升级成轻量级锁?
- 当线程访问带有偏向锁的资源,会使用CAS尝试获取
- 根据自适应自旋算法,自旋到一定次数还没获取到,会升级成重量级锁
19.谈谈重量级锁。
- 清理级锁一直自旋获取失败,会升级成重量级锁
- 重量级锁依赖于操作系统互斥量实现,线程进入阻塞状态
- 进入阻塞状态将不在销毁资源,但是唤醒需要更长的时间