JVM基础连环问
JVM基础连环问
什么是堆吗?
堆用于存放对象实例,是垃圾收集器管理的主要区域,因此也被称作GC
堆。堆可以细分为:新生代(Eden
空间、From Survivor
、To Survivor
空间)和老年代。
堆栈的区别?
- 堆的物理地址分配是不连续的,性能较慢;栈的物理地址分配是连续的,性能相对较快。
- 堆存放的是对象的实例和数组;栈存放的是局部变量,操作数栈,返回结果等。
- 堆是线程共享的;栈是线程私有的。
了解双亲委派模型吗?
- 当类载器收到一个类的加载请求时,它首先不会自己尝试去加载它,而是把这个请求委派给父类加载器去完成,这样层层委派,因此所有的加载请求最终都会传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。
- 双亲委派模型的具体实现代码在
java.lang.ClassLoader
中,此类的loadClass()
方法运行过程如下:先检查类是否已经加载过,如果没有则让父类加载器去加载。当父类加载器加载失败时抛出ClassNotFoundException
,此时尝试自己去加载。源码如下:
public abstract class ClassLoader {
// The parent class loader for delegation
private final ClassLoader parent;
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
}
为什么需要双亲委派模型呢?
- 假如没有双亲委派模型而是由各个类加载器自行加载的话,内存里面可能会出现多个相同的类。
- 比如用户编写了一个
java.lang.Object
的同名类并放在ClassPath
中,多个类加载器都去加载这个类到内存中,系统中将会出现多个不同的Object
类,那么类之间的比较结果及类的唯一性将无法保证。
什么是类加载器呢?
- 类加载器就是加载所有的类的工具,它加载的类在内存中只会存在一份,也就是堆中的Class对象。不可以重复加载
- Java 文件在经过 Java 编译器编译之后就被转换成 Java 字节码(class 文件)。类加载器负责读取 Java 字节码,并转换成
java.lang.Class
类的一个实例。
有哪些类加载器吗?
- 启动类加载器:用来加载 Java 核心类库,无法被 Java 程序直接引用。
- 扩展类加载器:它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
- 系统类加载器:它根据应用的类路径来加载 Java 类。可通过
ClassLoader.getSystemClassLoader()
获取它。 - 自定义类加载器:通过继承
java.lang.ClassLoader
类的方式实现。
怎么判断一个对象是否存活?
-
引用计数法。给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的。
-
可达性分析。通过
GC Root
对象为起点,从这些节点向下搜索,搜索所走过的路径叫引用链,当一个对象到GC Root
没有任何的引用链相连时,说明这个对象是不可用的。
可以作为GC Roots的对象有哪些呢?
- 虚拟机栈中引用的对象
- 本地方法栈中Native方法引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象