JVM面试点
1.java内存区域(运行时数据区)
jdk1.8以后我们将线程公共的变为堆,线程私有的变成了虚拟机栈,本地方法栈和程序计数器了。而另外一部分就是直接内存和元空间(就是之前的公共的方法区);
程序计数器
理解成自己码执行的行数指示器。字节码解释器通过改变程序计数器来选取下一条字节码。另外,线程的就绪,等待和切换的操作也要程序计数器来保存执行到的位置。
java虚拟机栈
其实就是一个栈帧,生命周期和线程一样,每次调用的数据都是通过栈传递的。随着线程的创建而创建,死亡而死亡。
虚拟机栈的两种异常
- StackOverFlowError:当虚拟机栈不允许动态拓展,而且当线程的请求栈深度超过了虚拟机栈的最大深度时就会抛出这个异常。
- OutOfMemoryError:当线程栈用完,而且无法再动态拓展时就会抛出这个异常。
将栈帧弹出的操作
- return语句 2. 抛出异常
本地方法栈
和虚拟机栈非常相似,为虚拟机栈服务。为虚拟机栈的Native方法服务。
堆
堆是虚拟机所管理的最大的一片区域,再虚拟机启动时自动创建。主要用来存放对象。也是GC垃圾回收的主要区域。
垃圾回收机制
java堆分为新时代(eden,s0,s1)和老年代(tentired)
回收步骤:
对象最开始会在eden区域进行分配,之后没有被去除的对象就会被分配到s0和s1区域。然后会循环分配。每次没有被回收的对象,年龄会+1,当年龄到默认值15的时候就会被分配到老年代。
方法区 -> 元空间
也是线程共享的区域,用于加载类信息,常量,静态变量,即使编译后的代码数据。
注意:再jdk1.8以后方法区被彻底的移除了。改为了元空间。元空间使用的时直接内存。元空间需要知道大小,随着更多类的创建可能会耗尽内存空间。
为什么要将方法区改为元空间:
方法区的大小受限与jvm本身固定上限。而元空间直接用直接内存。所以大小只会受限于计算机内存大小。
运行时常量池
jdk1.7之前属于方法区,1.7以及之后移出来了,到了堆区域。
直接内存
直接内存不属于虚拟机运行时数据区部分,也不属于虚拟机规范中定义的部分。但是这部分引用非常频繁,所以也有可能出现OutOfMemoryError异常。
2.java对象创建具体过程
1.类加载检查
虚拟机在遇到new指令的时候,会再常量池中检查是否有这个类的符号引用,并检查这个类是否以及被加载,解析和初始化过。如果没有则进行相应类加载过程。
2.内存分配
当类加载检查过了之后就会,虚拟机就会为新生对象分配内存。
3.初始化零值
这里保证了,类的成员属性在不赋值就能直接使用
4.设置对象头
将这个实例属于哪个类,类元数据信息,哈希码,GC分代年龄值等信息放在对象头。
执行init方法
在init方法执行前,对象的所有字段都还为0或者空。在执行init方法之后对象就真正的创建成功了。
3. 对象访问定位的两种方式
程序通过栈上面的reference数据来操作堆上面的具体对象。具体有两种访问方式,
- 使用句柄
- 直接指针
使用句柄
如果使用句柄的话,堆会开辟一个句柄空间,reference里存储的就是对象的句柄地址,句柄里面包含了类的一些信息的句柄地址。
使用直接指针
栈的reference就是直接指向堆里面的对象地址。
4.堆对象的分配机制
就是联合GC机制的。eden区最先用来存放开始没有清除掉的对象,接下来时s0和s1区。大的对象和年龄超过15的对象会被放入老年区。
5.Minor GC 和 Full GC
- MinorGC发生在eden区满了之后,调用非常的频繁,运行速度也块
- Full GC/Major GC 发生在老年代,运行速度慢。
6.判断对象是否死亡方式(两种)
引用计数法
给对象一个计数器,当找到一个对象的引用,计数器+1,当引用是失效的,计数器就-1。如果最后计数器为0,表示对象死亡,可以被GC了。
可达性分析法
通过“GC Root”为起点,从这些节点开始往下搜索,当一个对象到GC Root没有任何引用链连接的话,表示这个对象以及失效。可以被GC了。
7.强引用,软引用,弱引用,虚引用
强引用
最强的引用,当一个对象为强引用的时候,垃圾回收不会回收它。
软引用
较弱于强引用,当内存空间足够就不会被回收,内存空间不够的时候就会被回收。可以加快垃圾回收机制,防止内存溢出。
弱引用
弱于软引用,拥有更短的生命周期
虚引用
相当于没有引用
8.如何判断一个常量是废弃常量
例子:比如一个字符串“abc”,当其没有被String对象引用的时候就会被当作废弃常量而清除。
9.一个类为无用类条件
- 这个类的没有了任何实例
- 这个类的类加载器ClassLoader以及被回收
- 类的Class对象没有在任何地方被引用
达到这三个条件,类就可能会被清楚,但也不是一定。
10.垃圾回收算法种类
- 标记删除法
- 复制算法
- 标记整理法
- 分代收集算法
11.类加载过程
加载,连接,初始化
有哪些类加载器
- BootStrapClassLoader:启动类加载器
- ExtensionClassLoader:扩展类加载器
- AppClassLoader:应用程序加载器
双亲委派机制
首先这个类的加载器会将请求给其父类,父类又会交给其父类,这样的话请求会一直交给最底层的类加载器。如果其不能加载请求,就会将请求传递给其子类,子类不能处理请求就又会交给其对应的子类。(这样就做到了由下至上,再由上至下的操作)
好处:保证了java的稳定运行,防止类被重复加载。