整理了10个经典又容易被疏忽的JVM面试题,谢谢阅读,大家加油哈
1. 对象一定分配在堆中吗?有没有了解逃逸分析技术?
「对象一定分配在堆中吗?」不一定的,JVM通过 「逃逸分析」 ,那些逃不出方法的对象会在栈上分配。
-
「什么是逃逸分析?」
逃逸分析(Escape Analysis),是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围,从而决定是否要将这个对象分配到堆上。
❝
逃逸分析是指分析指针动态范围的方法,它同编译器优化原理的指针分析和外形分析相关联。当变量(或者对象)在方法中分配后,其指针有可能被返回或者被全局引用,这样就会被其他方法或者线程所引用,这种现象称作指针(或者引用)的逃逸(Escape)。通俗点讲,如果一个对象的指针被多个方法或者线程引用时,那么我们就称这个对象的指针发生了逃逸。
❞
-
「一个逃逸分析的例子」
/**
* @author 捡田螺的小男孩
*/
public class EscapeAnalysisTest {
public static Object object;
//StringBuilder可能被其他方法改变,逃逸到了方法外部。
public StringBuilder escape(String a, String b) {
//公众号:捡田螺的小男孩
StringBuilder str = new StringBuilder();
str.append(a);
str.append(b);
return str;
}
//不直接返回StringBuffer,不发生逃逸
public String notEscape(String a, String b) {
//公众号:捡田螺的小男孩
StringBuilder str = new StringBuilder();
str.append(a);
str.append(b);
return str.toString();
}
//外部线程可见object,发生逃逸
public void objectEscape(){
object = new Object();
}
//仅方法内部可见,不发生逃逸
public void objectNotEscape(){
Object object = new Object();
}
}
「逃逸分析的好处」
❝
-
栈上分配,可以降低垃圾收集器运行的频率。
-
同步消除,如果发现某个对象只能从一个线程可访问,那么在这个对象上的操作可以不需要同步。
-
标量替换,把对象分解成一个个基本类型,并且内存分配不再是分配在堆上,而是分配在栈上。这样的好处有,一、减少内存使用,因为不用生成对象头。二、程序内存回收效率高,并且GC频率也会减少。
❞
2.虚拟机为什么使用元空间替换了永久代?
「什么是元空间?什么是永久代?为什么用元空间代替永久代?」我们先回顾一下 「方法区」 吧,看看虚拟机运行时数据内存图,如下:
❝
方法区和堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
❞
「什么是永久代?它和方法区有什么关系呢?」
❝
如果在HotSpot虚拟机上开发、部署,很多程序员都把方法区称作永久代。可以说方法区是规范,永久代是Hotspot针对该规范进行的实现。在Java7及以前的版本,方法区都是永久代实现的。
❞
「什么是元空间?它和方法区有什么关系呢?」
❝
对于Java8,HotSpots取消了永久代,取而代之的是元空间(Metaspace)。换句话说,就是方法区还是在的,只是实现变了,从永久代变为元空间了。
❞
「为什么使用元空间替换了永久代?」
-
永久代的方法区,和堆使用的物理内存是连续的。
「永久代」是通过以下这两个参数配置大小的~
-
-XX:PremSize:设置永久代的初始大小
-
-XX:MaxPermSize: 设置永久代的最大值,默认是64M
对于 「永久代」 ,如果动态生成很多class的话,就很可能出现 「java.lang.OutOfMemoryError: PermGen space错误」 ,因为永久代空间配置有限嘛。最典型的场景是,在w