JVM 内存区域

JVM 内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区域【Java 堆、方法区】、直接内存。
(在 Hotspot VM 内,每个线程都与操作系统的本地线程直接映射,因此这部分内存区域的存/否跟随本地线程的生/死对应)。:在 JDK 1.4 引入的 NIO 提供了基于 Channel 与 Buffer 的 IO 方式,它可以使用 Native 函数库直接分配堆外内存,然后使用 DirectByteBuffer 对象作为这块内存的引用进行操作,这样就可以避免了在 Java 堆和 Native 堆中的来回复制数据,因此在一些场景中可以显著提高性能。
程序计数器(线程私有)
一块较小的内存空间,,每个线程都要有一个独立的程序计数器,这类内存也称为“线程私有”的内存。
如果线程正在执行 Java 方法的话,程序计数器记录的是虚拟机字节码指令的地址
(当前指令的地址)。如果是 Native 方法,则为空。
这个内存区域是唯一一个在虚拟机中没有规定任何 OutOfMemoryError 情况的区域。
虚拟机栈(线程私有)
栈帧(Frame)是用来存储数据
和部分过程结果
的数据结构,同时也被用来处理动态链接(Dynamic Linking)
、方法返回值
和异常分派(Dispatch Exception)
。。无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束。

本地方法区(线程私有)
本地方法区
和 Java Stack
作用类似,区别是,如果一个 VM 实现使用 C-linkage 模型来支持 Native 调用,那么该栈将会是一个 C 栈,但 Hotspot VM 直接就把本地方法栈和虚拟机合二为一了。
堆(Heap-线程共享)-运行时数据区
堆是被线程共享的一块内存区域,。由于现代 VM 采用分代收集算法
,因此 Java 堆从 GC 的角度还可以细分为:新生代
(Eden 区、From Survivor区、和 To Survivor区)和老年代
。
方法区/永久代(线程共享)
方法区就是我们常说的永久代(Permanent Generation),用于存储被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Hotspot VM 把 GC 分代收集扩展至方法区,即使用 Java 堆的永久代来实现方法区,这样 Hotspot 的垃圾收集器就可以像管理 Java 堆一样管理这部分内存,而不必为方法区开发专门的内存管理器(永久代的内存回收的主要目标是针对常量池的回收和类型的卸载,因此受益一般很小)。
是方法区的一部分,Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量
和符号引用
,这部分内容将在类加载后存放到方法区的运行时常量池中。Java 虚拟机对 Class 文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储那种数据都必须符合规范上的要求。这样才会被虚拟机认可、装载和执行。