Java面试题冲刺第二十一天--JVM
一、了解JVM
1. JVM的概念
JVM(Java Virtual Machine)即Java虚拟机,是Java语言的运行环境,负责将Java字节码文件转换为机器指令执行。
2. JVM的内部结构
JVM的内部结构分为三个部分:类加载器,运行时数据区,执行引擎。
2.1 类加载器
用来加载类文件,包括如下几种类型:
-
Bootstrap ClassLoader:启动类加载器,用来加载JVM自身的类,在Classpath中找不到。
-
Extension ClassLoader:扩展类加载器,用来加载JRE中的类库,在Classpath中找不到。
-
System/Application ClassLoader:系统类加载器,用来加载应用程序中的类,在Classpath中找到。
2.2 运行时数据区
JVM运行时数据区分为如下几个部分:
-
程序计数器:当前线程执行的字节码的行号记录器。
-
Java虚拟机栈:每个线程独享一块区域,用来存储方法执行过程中的局部变量、操作数栈、动态连接、方法出口等信息。
-
本地方法栈:用来执行本地方法的调用,如C语言代码等。
-
Java堆:存储Java对象的区域,由新生代和老年代两个子区域组成。
-
方法区:用来存储已加载的类信息、常量、静态变量等等。
2.3 执行引擎
执行引擎是JVM的最核心的部分,它负责将字节码转换为机器指令执行。
二、JVM的垃圾回收
1. 垃圾回收的概念
垃圾回收就是在程序运行过程中,GC(Garbage Collector,垃圾回收器)自动释放已经不再需要的内存。
2. 垃圾回收算法
目前主流的垃圾回收算法包括如下几种:
-
标记-清除算法:先标记所有需要回收的对象,再统一进行回收。
-
复制算法:将内存分为两个区域,每次使用其中一个区域,当这个区域使用完后,将存活的对象复制到另一个区域中。
-
标记-整理算法:在标记完成之后,将存活的对象向一端移动,然后在端点之后所有的空间全部释放。
3. 垃圾回收器
垃圾回收器的种类有很多,包括:
-
Serial收集器:单线程的独占式收集器,适合于小型程序。
-
ParNew收集器:Serial收集器的多线程版本,适合于多CPU的环境。
-
CMS收集器:并发标记清除收集器,支持低延迟的垃圾回收。
-
G1收集器:并发标记整理收集器,支持更大的堆,更高效的垃圾回收。
三、关于内存分配和回收
1. Java堆的内存划分
Java堆分为新生代和老年代两个区域,新生代又分为Eden区和Survivor区(From和To)。
2. 内存分配和回收策略
内存分配和回收策略有如下几种:
-
对象优先在Eden区分配,如果Eden区没有足够空间,则将存活的对象放进Survivor区,如果Survivor区满了,采用复制算法将存活对象复制到另一个Survivor区中,如果两个Survivor区都满了,则采用老年代进行分配。
-
大对象直接进入老年代,如一个大的数组或字符串等。
-
长期存活的对象将进入老年代,设置阈值参数,当对象在Survivor区中熬过了15轮,则将对象移动到老年代中。
3. 内存泄漏
内存泄漏是指程序中存在不能访问的对象,但是却仍然占用着内存,导致程序运行过程中内存耗尽。
四、示例说明
示例一
编写如下代码:
public void foo() {
String str = "hello";
System.out.println(str);
}
首先,JVM会在程序启动时加载java.lang.Object
类,还会预先加载其他常用的类。
然后,JVM会在当前线程的Java虚拟机栈中压入一个栈帧,每个栈帧中包含了局部变量、操作数栈、调用者栈帧地址等信息。
在foo()
方法执行到String str = "hello"
语句时,JVM会在栈帧的局部变量表中分配一个String
类型变量str
,并将值设置为hello
。
最后,在System.out.println(str)
语句执行时,JVM会调用System.out
对象的println()
方法,并将str
作为参数传递过去。
示例二
编写如下代码:
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello, my name is " + name + ", and I am " + age + " years old.");
}
}
在Java虚拟机中,会有一个类加载器,用来加载所有的类。
在程序执行到Person person = new Person("张三", 20)
语句时,JVM会先检查是否已经加载了Person
类,如果没有则使用类加载器加载该类。
当类被加载之后,JVM会在堆中分配一个内存区域作为Person
类型变量的实例对象。这个区域包含了对象的所有属性值,如name
和age
等。
最后,当程序执行到person.sayHello()
时,JVM会执行该方法,其中name
和age
属性值会作为参数传递到System.out.println()
方法中,实现输出信息的功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java面试题冲刺第二十一天–JVM - Python技术站