目录
一、JVM学习
1,JVM内存模型?
2,JVM类加载机制?
3,String s = "aaa",类似这些题目?
二、JVM面试题
2.1详细jvm内存模型
2.2讲讲什么情况下回出现内存溢出,内存泄漏?
2.3说说线程栈
2.4JVM 年轻代到年老代的晋升过程的判断条件是什么呢?
2.5JVM 出现 fullGC 很频繁,怎么去线上排查问题
2.6类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?
2.7类的实例化顺序
2.8JVM垃圾回收机制,何时触发MinorGC等操作
2.9JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的
2.10各种回收算法
2.11各种回收器,各自优缺点,重点CMS、G1
2.12stackoverflow错误,permgen space错误
2019.09.26 面试题总结,基础决定走多远。Persist!
工作过程:
其实这就是所谓的双亲委派模型。简单来说:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上。
好处:
特别说明:
java.lang.Class
类的实例缓存起来。下次再请求加载该类的时候,类加载器会直接使用缓存的类的实例,而不会尝试再次加载。类加载过程(加载-->连接(验证,准备,解析)-->初始化)
String s = "aaa",
类似这些题目?常量池存储的是:
常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放--->来源:深入理解Java虚拟机 JVM高级特性与最佳实践(第二版)
现在我们的运行时常量池只是换了一个位置(原本来方法区,现在在堆中),但可以明确的是:类加载后,常量池中的数据会在运行时常量池中存放!
HotSpot VM里,记录interned string的一个全局表叫做StringTable,它本质上就是个HashSet
。注意它只存储对java.lang.String实例的引用,而不存储String对象的内容
字符串常量池只存储引用,不存储内容!
再来看一下我们的intern方法:
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
*当调用intern方法时,如果池已包含
*字符串等于此{@code string}对象,由
*{@link equals(object)}方法,则池中的字符串是
*返回。否则,此{@code string}对象将添加到
*返回池和对此{@code string}对象的引用。
以下面试题引用自大神https://my.oschina.net/u/2935389 群星纪元。
拿些常见的JVM面试题来做做,加深一下理解和查缺补漏:
题目来源:
根据 JVM 规范,JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。
具体可能会聊聊jdk1.7以前的PermGen(永久代),替换成Metaspace(元空间)
图片来源:https://blog.csdn.net/tophawk/article/details/78704074
参考资料:
内存泄漏的原因很简单:
常见的内存泄漏例子:
public static void main(String[] args) {
Set set = new HashSet();
for (int i = 0; i < 10; i++) {
Object object = new Object();
set.add(object);
// 设置为空,这对象我不再用了
object = null;
}
// 但是set集合中还维护这obj的引用,gc不会回收object对象
System.out.println(set);
}
解决这个内存泄漏问题也很简单,将set设置为null,那就可以避免上诉内存泄漏问题了。其他内存泄漏得一步一步分析了。
内存泄漏参考资料:
内存溢出的原因:
解决:
参考资料:
这里的线程栈应该指的是虚拟机栈吧...
JVM规范让每个Java线程拥有自己的独立的JVM栈,也就是Java方法的调用栈。
当方法调用的时候,会生成一个栈帧。栈帧是保存在虚拟机栈中的,栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息
线程运行过程中,只有一个栈帧是处于活跃状态,称为“当前活跃栈帧”,当前活动栈帧始终是虚拟机栈的栈顶元素。
通过jstack工具查看线程状态
参考资料:
这题就依据full GC的触发条件来做:
- 所以看看是不是perm gen区的值设置得太小了。
System.gc()
方法的调用- 这个一般没人去调用吧~~~
- 是不是频繁创建了大对象(也有可能eden区设置过小)(大对象直接分配在老年代中,导致老年代空间不足--->从而频繁gc) - 是不是老年代的空间设置过小了(Minor GC几个对象就大于老年代的剩余空间了)
双亲委托模型的重要用途是为了解决类载入过程中的安全性问题。
java.lang.Object
的类,想借此欺骗JVM。现在他要使用自定义ClassLoader
来加载自己编写的java.lang.Object
类。Bootstrap ClassLoader
的路径下找到java.lang.Object
类,并载入它Java的类加载是否一定遵循双亲委托模型?
- https://zhuanlan.zhihu.com/p/28909673 - https://www.cnblogs.com/huzi007/p/6679215.html - https://blog.csdn.net/sigangjun/article/details/79071850
参考资料:
检验一下是不是真懂了:
class Dervied extends Base {
private String name = "Java3y";
public Dervied() {
tellName();
printName();
}
public void tellName() {
System.out.println("Dervied tell name: " + name);
}
public void printName() {
System.out.println("Dervied print name: " + name);
}
public static void main(String[] args) {
new Dervied();
}
}
class Base {
private String name = "公众号";
public Base() {
tellName();
printName();
}
public void tellName() {
System.out.println("Base tell name: " + name);
}
public void printName() {
System.out.println("Base print name: " + name);
}
}
输出数据:
Dervied tell name: null
Dervied print name: null
Dervied tell name: Java3y
Dervied print name: Java3y
第一次做错的同学点个赞,加个关注不过分吧(hahaha
当young gen中的eden区分配满的时候触发MinorGC(新生代的空间不够放的时候).
这题不是很明白意思(水平有限...如果知道这题的意思可在评论区留言呀~~)
YGC和FGC是什么
什么时候执行YGC和FGC
System.gc()
,ygc时的悲观策略, dump live的内存信息时(jmap –dump:live),都会执行full gcGC最基础的算法有三种:
具体:
图来源于《深入理解Java虚拟机:JVM高级特效与最佳实现》,图中两个收集器之间有连线,说明它们可以配合使用.
stackoverflow错误主要出现:
permgen space错误(针对jdk之前1.7版本):