JVM (Java Virtual Machine) 是 Java 编程语言的运行环境,它是一个虚拟的计算机,可以在不同的操作系统上运行 Java 程序。JVM 是 Java 的核心部分,提供了将 Java 代码翻译成特定计算机系统指令的功能。以下是 JVM 的一些重要概念和原理的详细说明:
类装载器(Class Loader):JVM 的类装载器负责将 Java 类加载到 JVM 中。类装载器有多个级别,主要负责加载 Java 核心类库和用户自定义类。
字节码执行引擎(Bytecode Execution Engine):JVM 的字节码执行引擎将 Java 字节码转换为可执行的机器码,并执行这些机器码。JVM 提供了多种执行引擎,如解释执行引擎和即时编译器。
即时编译器(Just-In-Time Compiler):JVM 的即时编译器将频繁执行的字节码转换为本地机器码,以提高程序的执行效率。即时编译器会对热点代码进行分析和优化。
垃圾回收器(Garbage Collector):JVM 的垃圾回收器负责自动回收不再使用的对象内存,以避免内存泄露和程序崩溃。垃圾回收器会周期性地扫描内存,标记和释放无效的对象。
内存管理系统(Memory Management System):JVM 的内存管理系统负责管理 Java 程序使用的内存。它将内存分成不同的区域,如堆区和栈区,以及方法区和运行时常量池等。
安全管理器(Security Manager):JVM 的安全管理器用于控制 Java 程序的访问权限。它通过安全策略文件来规定程序可访问的资源和操作。
多线程支持(Multithreading Support):JVM 支持多线程并发执行,可以通过多线程编程实现并行计算和提高程序的性能。
JVM(Java虚拟机)的主要组成包括以下几个部分:
程序计数器是一块较小的内存区域,它是线程私有的,其作用是记录当前线程所执行的字节码指令的位置。当线程被切换时,通过程序计数器可以准确地恢复到正确的执行位置。程序计数器在多线程间切换和控制线程执行顺序等方面起到重要作用。
javap -v 类名? ? ?字节码文件里面执行即可
Java堆(Java Heap)是JVM中最大的一块内存区域,用于存储对象实例。所有的Java对象实例和数组都在堆中分配内存。堆是所有线程共享的,而且是垃圾回收的重点区域。
它被分成新生代和老年代两部分,新对象在新生代分配,而较长时间存活的对象会被移动到老年代。堆的大小可以通过JVM的启动参数进行设置。
Eden区:新创建的对象首先被分配到Eden区,它是新生代中最大的区域。当Eden区满时,就会触发一次Minor GC(Minor Garbage Collection,新生代垃圾回收)。在Minor GC中,Eden区中存活的对象会被复制到Survivor区。
Survivor区:Survivor区是两个较小的区域,称为S0和S1。当一次Minor GC发生时,存活的对象会被复制到另一个Survivor区中,并且年龄加一。当某个对象在Survivor区中经过多次复制仍然存活,就会被晋升到老年代。
老年代中的对象一般需要经过多次的垃圾回收才会被清理掉。当老年代空间不足时,就会触发一次Major GC(Major Garbage Collection,全局垃圾回收),即进行一次完整的垃圾回收,包括新生代和老年代的垃圾回收。
需要注意的是,除了新生代和老年代之外,在Java堆中还有一些其他的区域,比如永久代(Permanent Generation)和元空间(Metaspace)。永久代主要存储类的信息、方法信息等,而元空间则用来存储这些信息。在Java 8及以上版本中,永久代已经被元空间取代。
在Java堆中,还包括了一个内存区域——方法区(Method Area)。方法区用于存储已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。它也被多个线程共享,而且是GC的主要回收区域。
方法区?
运行时常量池是Java虚拟机在运行时动态创建的一个存放常量的区域,它是方法区的一部分。在Java源代码中,所有的字面量(如字符串、数字、符号等)都被称为常量,并且它们都会被编译器放入到常量池中。而运行时常量池则是在类加载完成后,将常量池中的符号引用替换为直接引用,并且可以进行动态的扩展。
运行时常量池中的常量包括两种类型:字面量常量和符号引用。字面量常量指的是字符串、数字等具体的值,而符号引用则是指向字符串字面量、类和接口的全限定名、字段的名称和描述符等。
运行时常量池的目的是为了提高程序的运行效率和节约内存空间。它可以在类加载时将常量池中的常量缓存在内存中,以减少频繁的创建和销毁。同时,它还可以对常量进行共享、重用,以节约内存的使用。
?
直接内存?
?
直接内存是一种由操作系统管理的内存,不受Java虚拟机(JVM)直接控制,也不直接受Java堆或方法区的限制。它是通过Java NIO(New Input/Output)库中的ByteBuffer来进行操作的。
直接内存位于操作系统的虚拟内存空间中,通常是通过调用操作系统的本地方法来分配和释放。
直接内存的作用是提供一种高效的内存操作方式,可以在对外部I/O进行高速读写时减少数据从Java堆复制到直接内存的开销。它可以通过零拷贝(Zero-copy)技术直接操作内存,提高数据读写的效率。
直接内存的实用之处在于它可以用来优化各种I/O操作,比如网络传输、文件操作、数据库连接等。直接内存还可以被用于创建内存映射文件,将一个文件直接映射到内存中,从而实现更加高效的文件读写操作。此外,直接内存还可以通过使用操作系统提供的一些特殊机制来实现堆外内存的分配和释放,从而避免了Java堆的GC压力。