JVM是什么?

发布时间:2023年12月22日

JVM (Java Virtual Machine) 是 Java 编程语言的运行环境,它是一个虚拟的计算机,可以在不同的操作系统上运行 Java 程序。JVM 是 Java 的核心部分,提供了将 Java 代码翻译成特定计算机系统指令的功能。以下是 JVM 的一些重要概念和原理的详细说明:

  1. 类装载器(Class Loader):JVM 的类装载器负责将 Java 类加载到 JVM 中。类装载器有多个级别,主要负责加载 Java 核心类库和用户自定义类。

  2. 字节码执行引擎(Bytecode Execution Engine):JVM 的字节码执行引擎将 Java 字节码转换为可执行的机器码,并执行这些机器码。JVM 提供了多种执行引擎,如解释执行引擎和即时编译器。

  3. 即时编译器(Just-In-Time Compiler):JVM 的即时编译器将频繁执行的字节码转换为本地机器码,以提高程序的执行效率。即时编译器会对热点代码进行分析和优化。

  4. 垃圾回收器(Garbage Collector):JVM 的垃圾回收器负责自动回收不再使用的对象内存,以避免内存泄露和程序崩溃。垃圾回收器会周期性地扫描内存,标记和释放无效的对象。

  5. 内存管理系统(Memory Management System):JVM 的内存管理系统负责管理 Java 程序使用的内存。它将内存分成不同的区域,如堆区和栈区,以及方法区和运行时常量池等。

  6. 安全管理器(Security Manager):JVM 的安全管理器用于控制 Java 程序的访问权限。它通过安全策略文件来规定程序可访问的资源和操作。

  7. 多线程支持(Multithreading Support):JVM 支持多线程并发执行,可以通过多线程编程实现并行计算和提高程序的性能。

JVM(Java虚拟机)的主要组成包括以下几个部分

  1. Class Loader(类加载器):负责将字节码文件加载到内存中,并转换成运行时数据结构(Class对象)。
  2. Execution Engine(执行引擎):负责执行Class对象中的字节码指令,通常有解释器和即时编译器两种方式。
  3. Java Native Interface(JNI):提供了与其他语言交互的接口,可以调用本地(C/C++)代码。
  4. Runtime Data Areas(运行时数据区):包含了一些内存区域,主要有程序计数器、Java堆、Java栈、方法区和本地方法栈等。

程序计数器是一块较小的内存区域,它是线程私有的,其作用是记录当前线程所执行的字节码指令的位置。当线程被切换时,通过程序计数器可以准确地恢复到正确的执行位置。程序计数器在多线程间切换和控制线程执行顺序等方面起到重要作用。

javap -v 类名? ? ?字节码文件里面执行即可

Java堆(Java Heap)是JVM中最大的一块内存区域,用于存储对象实例。所有的Java对象实例和数组都在堆中分配内存。堆是所有线程共享的,而且是垃圾回收的重点区域。

它被分成新生代和老年代两部分,新对象在新生代分配,而较长时间存活的对象会被移动到老年代。堆的大小可以通过JVM的启动参数进行设置。

  1. 新生代(Young Generation): 新生代是Java堆中的一部分,用于存储新创建的对象。在新生代中,又分为三个部分:Eden区、Survivor区(S0和S1)。
  • Eden区:新创建的对象首先被分配到Eden区,它是新生代中最大的区域。当Eden区满时,就会触发一次Minor GC(Minor Garbage Collection,新生代垃圾回收)。在Minor GC中,Eden区中存活的对象会被复制到Survivor区。

  • Survivor区:Survivor区是两个较小的区域,称为S0和S1。当一次Minor GC发生时,存活的对象会被复制到另一个Survivor区中,并且年龄加一。当某个对象在Survivor区中经过多次复制仍然存活,就会被晋升到老年代。

  1. 老年代(Old Generation): 老年代是Java堆中的另一部分,用于存储长时间存活的对象。在新生代中经过多次复制仍然存活的对象,会被晋升到老年代。老年代相对于新生代来说,其大小一般较大,并且存放的是相对较长时间存活的对象。

老年代中的对象一般需要经过多次的垃圾回收才会被清理掉。当老年代空间不足时,就会触发一次Major GC(Major Garbage Collection,全局垃圾回收),即进行一次完整的垃圾回收,包括新生代和老年代的垃圾回收。

需要注意的是,除了新生代和老年代之外,在Java堆中还有一些其他的区域,比如永久代(Permanent Generation)和元空间(Metaspace)。永久代主要存储类的信息、方法信息等,而元空间则用来存储这些信息。在Java 8及以上版本中,永久代已经被元空间取代。

在Java堆中,还包括了一个内存区域——方法区(Method Area)。方法区用于存储已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。它也被多个线程共享,而且是GC的主要回收区域。

  1. 虚拟机栈是Java虚拟机在运行Java程序时所使用的一块内存区域,用于存储局部变量、方法调用和返回的信息。
  2. 虚拟机栈是线程私有的,每个线程都有自己的虚拟机栈,因此是线程安全的。
  3. 每个栈由栈帧组成,栈帧用于存储方法的局部变量表、操作数栈、动态链接信息、方法返回地址以及一些额外的附加信息。
  4. 垃圾回收一般不涉及栈内存,因为虚拟机栈中的栈帧会随着方法的调用和返回而动态地入栈和出栈,当方法调用结束后,栈帧会自动被销毁,不需要进行垃圾回收。
  5. 栈内存的分配大小取决于系统的设计和限制,过大的栈内存可能会导致系统资源的浪费,而过小的栈内存可能会导致栈溢出的问题。所以栈内存的大小应根据具体应用的需求进行合理的配置。
  6. 方法内的局部变量只在方法的执行期间存在,并且每个线程都会有自己的副本,在方法内部是线程安全的。但是如果一个局部变量被多个线程共享或作为实例变量,可能需要考虑线程安全性。
  7. 栈内存溢出情况通常指虚拟机栈的溢出,即栈帧过多导致栈空间不足。当调用深度过大或者栈帧太大时,都可能导致栈内存溢出。溢出时会抛出StackOverflowError或OutOfMemoryError异常。

方法区?

  1. 方法区(Method Area)是Java虚拟机的一部分,用于存储类的结构信息、常量、静态变量、即时编译器编译后的代码等数据。
  2. 方法区的作用是用于存储类的相关信息,包括类的成员变量、方法、构造函数等。同时,方法区还用于存储类的常量池、字节码等。
  3. 方法区位于Java虚拟机的堆之外,通常与堆分开并行回收。具体的位置可以根据虚拟机的实现而有所不同。
  4. 常量池(Constant Pool)是方法区的一块重要部分,用于存储编译期生成的各种字面量和符号引用。常量池的作用是为了提供一种节省空间和方便使用的方式,存储字符串、数字、类、方法、字段等常量。在执行时,可以通过常量池中的索引快速定位到具体的常量值。常量池的执行是在编译期完成的,编译器会将常量值直接存储在常量池中,并在运行时进行引用。
  5. 运行时常量池是Java虚拟机在运行时动态创建的一个存放常量的区域,它是方法区的一部分。在Java源代码中,所有的字面量(如字符串、数字、符号等)都被称为常量,并且它们都会被编译器放入到常量池中。而运行时常量池则是在类加载完成后,将常量池中的符号引用替换为直接引用,并且可以进行动态的扩展。

    运行时常量池中的常量包括两种类型:字面量常量和符号引用。字面量常量指的是字符串、数字等具体的值,而符号引用则是指向字符串字面量、类和接口的全限定名、字段的名称和描述符等。

    运行时常量池的目的是为了提高程序的运行效率和节约内存空间。它可以在类加载时将常量池中的常量缓存在内存中,以减少频繁的创建和销毁。同时,它还可以对常量进行共享、重用,以节约内存的使用。

?

直接内存?

?

  1. 直接内存是一种由操作系统管理的内存,不受Java虚拟机(JVM)直接控制,也不直接受Java堆或方法区的限制。它是通过Java NIO(New Input/Output)库中的ByteBuffer来进行操作的。

  2. 直接内存位于操作系统的虚拟内存空间中,通常是通过调用操作系统的本地方法来分配和释放。

  3. 直接内存的作用是提供一种高效的内存操作方式,可以在对外部I/O进行高速读写时减少数据从Java堆复制到直接内存的开销。它可以通过零拷贝(Zero-copy)技术直接操作内存,提高数据读写的效率。

  4. 直接内存的实用之处在于它可以用来优化各种I/O操作,比如网络传输、文件操作、数据库连接等。直接内存还可以被用于创建内存映射文件,将一个文件直接映射到内存中,从而实现更加高效的文件读写操作。此外,直接内存还可以通过使用操作系统提供的一些特殊机制来实现堆外内存的分配和释放,从而避免了Java堆的GC压力。

文章来源:https://blog.csdn.net/Flying_Fish_roe/article/details/135101312
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。