JVM 内存区域详解(3)

JVM 内存区域详解(3)

运行时常量池

​ Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有用于存放编译期生成的各种字面(Literal)和符号引用(Symbolic Reference)的 常量池表(Constant Pool Table)

​ 字面量是源代码中的固定值的表示法,即通过字面我们就能知道其值的含义。字面量包括整数、浮点数和字符串字面两。常见的符号引用包括类符号引用、字段符号引用、方法符号引用、接口方法符号。

​ 《深入理解 Java 虚拟机》7.34 节第三版对符号引用和直接引用的解释如下:

符号引用和直接引用

​ 常量池表会在类加载后存放到方法区的运行时常量池中

​ 运行时常量池的功能类似于传统编程语言的符号表,尽管它包含了比典型符号表更广泛的数据。

​ 既然运行时常量池是方法区的一部分,自然收到方法区的内存限制,当常量池无法再申请到内存时会抛出 OOM 错误

字符串常量池

字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。

​ HotSpot 虚拟机中字符串常量池的实现是 stringTable.cpp StringTable 可以简单理解为一个固定大小的 HashTable 容量可以通过参数来设定,保存的是字符串 key 和字符串对象的引用的映射关系,字符串对象的引用指向堆中的字符串对象。

​ JDK 1.7 之前,字符串常量池存放在永久代。JDK 1.7 字符串常量池和静态变量从永久代移动到 Java 堆中。

method-area-jdk1.6

method-area-jdk1.7

JDK 1.7 为什么要把字符串常量池移动到堆中

​ 主要是因为永久代 (方法区的实现)的 GC 回收效率太低,对永久代的 GC 需要满足一系列复杂的条件且不一定能够完美回收,而 Java 中对于字符串的创建是非常频繁的,将字符串常量池放入堆中,能够更高效的及时回收字符串内存。

直接内存

​ 直接内存是一种特殊的内存缓冲区域,并不在 Java 堆或方法区中分配的,而是通过 JNI 的方式在本地内存上分配的。

​ 直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁的使用。而且也可能导致 OOM 错误出现。

​ JDK 1.4 中新加入的 NIO (New I/O 也被称作 Non-Blocking I/O),引入了一种基于通道的(Channel)与缓存区 (Buffer)的I/O 方式,它可以直接使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中 DirectByteBuffer 对象作为这块内存的引用进行操作。这样就能在一些场景中显著提升性能,因为避免了 Java 堆 Native 堆之间来回复制数据。

​ 直接内存的分配不会收到 Java 堆的限制,但是,既然是内存就会收到本机的总内存大小以及处理器寻址空间的限制。

va 堆的限制,但是,既然是内存就会收到本机的总内存大小以及处理器寻址空间的限制。

​ 类似的概念还有 堆外内存 。 堆外内存就使把内存对象分配在堆之外的内存,这些内存直接受操作系统管理(而不是虚拟机),这样做的后果就使能够一定程度上减少垃圾回收对应用造成的影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值