(JVM1)Java内存区域与内存溢出异常之二
2017-03-18 22:11
483 查看
写这篇文章,主要是为了记录自己复习Java虚拟机的一些心得总结笔记,仅供分享参考学习,如有不对的地方,敬请指正。
今天要是要说的是:运行时常量池(Runtime Constant Pool),直接内存(Direct Memory)。
本文中提到的字面量、符号引用、直接引用等词将在本文的后面做出解释。
并非预置入Class文件中常量池的内容才能进入方法区的运行时常量池,运行期间也可能将新的常量放入池中,例如String类的intern()方法。
我们知道,方法区是放在内存中的,而运行时常量池是在方法区中的,那么就可能出现申请不到内存的情况,所以,它也有OutOfMemoryError。
在JDK1.4中加入了NIO(New Input/Output),它是基于通道(Channel)与缓冲区(Buffer)的,它能使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能显著提高性能,因为避免了在java堆和Native堆中来回复制数据。
显然,它并不会收到java堆内存的限制,只受限于服务器本身的内存。
在设置-Xmx等参数时,为了避免各个内存区域总和大于物理内存限制,必须将直接内存考虑进去,以免导致直接内存区域内存不足而出现OutOfMemoryError异常。
下面,介绍一下上面提到的字面量等词。
1、java字面量:
int i = 1;把整数1赋值给int型变量i,整数1就是Java字面量,
同样,String s = "abc";中的abc也是字面量。
2、符号引用
符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能够无歧义的定位到目标即可。例如,在Class文件中它以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等类型的常量出现。符号引用与虚拟机的内存布局无关,引用的目标并不一定加载到内存中。在Java中,一个java类将会编译成一个class文件。在编译时,java类并不知道所引用的类的实际地址,因此只能使用符号引用来代替。比如org.simple.People类引用了org.simple.Language类,在编译时People类并不知道Language类的实际内存地址,因此只能使用符号org.simple.Language(假设是这个,当然实际中是由类似于CONSTANT_Class_info的常量来表示的)来表示Language类的地址。各种虚拟机实现的内存布局可能有所不同,但是它们能接受的符号引用都是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。
3、直接引用
直接引用可以是
(1)直接指向目标的指针(比如,指向“类型”【Class对象】、类变量、类方法的直接引用可能是指向方法区的指针)
(2)相对偏移量(比如,指向实例变量、实例方法的直接引用都是偏移量)
(3)一个能间接定位到目标的句柄
直接引用是和虚拟机的布局相关的,同一个符号引用在不同的虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经被加载入内存中了。
本文参考了以下文章:
http://blog.csdn.net/u010850285/article/details/44152157 http://blog.csdn.net/u014656992/article/details/51107127
今天要是要说的是:运行时常量池(Runtime Constant Pool),直接内存(Direct Memory)。
本文中提到的字面量、符号引用、直接引用等词将在本文的后面做出解释。
1、运行时常量池
运行时常量池是方法区的一部分(关于方法区的说明,清考我我的文章Java内存区域与内存溢出异常)。它用于存放编译期生成的各种字面量和符号引用,这部分内存将在类加载后进入方法区的运行时常量池中存放。除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。并非预置入Class文件中常量池的内容才能进入方法区的运行时常量池,运行期间也可能将新的常量放入池中,例如String类的intern()方法。
我们知道,方法区是放在内存中的,而运行时常量池是在方法区中的,那么就可能出现申请不到内存的情况,所以,它也有OutOfMemoryError。
2、直接内存
直接内存并不是虚拟机运行时数据区的一部分,也不是JVM规范中定义的内存区域。因为它被频繁使用并且可能出现OutOfMemoryError,所以这里需要说一下。在JDK1.4中加入了NIO(New Input/Output),它是基于通道(Channel)与缓冲区(Buffer)的,它能使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能显著提高性能,因为避免了在java堆和Native堆中来回复制数据。
显然,它并不会收到java堆内存的限制,只受限于服务器本身的内存。
在设置-Xmx等参数时,为了避免各个内存区域总和大于物理内存限制,必须将直接内存考虑进去,以免导致直接内存区域内存不足而出现OutOfMemoryError异常。
下面,介绍一下上面提到的字面量等词。
1、java字面量:
int i = 1;把整数1赋值给int型变量i,整数1就是Java字面量,
同样,String s = "abc";中的abc也是字面量。
2、符号引用
符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能够无歧义的定位到目标即可。例如,在Class文件中它以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等类型的常量出现。符号引用与虚拟机的内存布局无关,引用的目标并不一定加载到内存中。在Java中,一个java类将会编译成一个class文件。在编译时,java类并不知道所引用的类的实际地址,因此只能使用符号引用来代替。比如org.simple.People类引用了org.simple.Language类,在编译时People类并不知道Language类的实际内存地址,因此只能使用符号org.simple.Language(假设是这个,当然实际中是由类似于CONSTANT_Class_info的常量来表示的)来表示Language类的地址。各种虚拟机实现的内存布局可能有所不同,但是它们能接受的符号引用都是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。
3、直接引用
直接引用可以是
(1)直接指向目标的指针(比如,指向“类型”【Class对象】、类变量、类方法的直接引用可能是指向方法区的指针)
(2)相对偏移量(比如,指向实例变量、实例方法的直接引用都是偏移量)
(3)一个能间接定位到目标的句柄
直接引用是和虚拟机的布局相关的,同一个符号引用在不同的虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经被加载入内存中了。
本文参考了以下文章:
http://blog.csdn.net/u010850285/article/details/44152157 http://blog.csdn.net/u014656992/article/details/51107127
相关文章推荐
- JVM 学习笔记1 JAVA内存区域与溢出异常
- Java基础--jvm(内存区域与内存溢出异常--运行时数据区域)
- jvm(1)----java内存区域与内存溢出异常
- Java内存区域与内存溢出异常与Eclipse运行速度调优
- JVM-自动内存管理机制之Java内存区域与内存溢出异常
- jvm笔记1--Java内存区域与内存溢出
- JVM:Java内存区域与内存溢出
- JVM--JAVA内存区域与内存溢出异常(未完)
- 深入理解JVM笔记一-java内存区域与内存溢出异常
- Java内存区域与内存溢出异常——运行时数据区域
- Java内存区域与内存溢出异常-内存区域
- Java内存区域与内存溢出异常-异常实战
- 深入java虚拟机 1 java内存区域与内存溢出的异常
- 第2章 Java内存区域与内存溢出异常--《深入理解 Java 虚拟机》笔记
- Java内存区域与内存溢出异常——对象
- JVM----内存区域及溢出异常
- 学习JVM之java内存区域与异常
- [课本划重点]深入理解jvm-第2章 java内存区域与内存溢出异常(1)
- JVM(一):Java内存区域与内存溢出异常
- (JVM1)Java内存区域与内存溢出异常