在jvm中有一块非常重要的区域,就是jvm运行时数据区。今天对该区域做下总结和记录:
在讨论jvm运行时数据区前,先说下jvm,jvm是一套规范,并不是实现,现在它的实现主要有hotspot(oracle),JRocket(oracle),J9(IBM)
正题
jvm运行时数据区总共分为5块:堆,方法区,java栈,本地方法栈,程序计数器。这些都是jvm规范,并不是实现,实现我会在下一节对hotspot重点讲解。
jvm运行时数据区1. 堆
线程共享,存放运行时产生的对象。在虚拟机启动时创建。
2. 方法区
线程共享,存放类型信息
3. 程序计数器
线程私有,是一块较小的内存空间,指示当前线程所执行的字节码行号。如果执行的是本地的方法,那么这个计数器值为空。
4. java栈
线程私有,生命周期与线程相同。每个java方法在栈里都是一个栈帧。栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法在调用到执行完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。
局部变量表存放了各种基本类型、对象引用、和returnAddress类型(指向一条字节码指令的地址)。
5. 本地方法栈
原理和java栈类似,是java调用其他语言的方法的存放区。
可以把每个java栈的大小适当调小一点,减少内存的使用量来提高系统的并发量。但是当栈空间调小以后,又会引发方法调用深度的的问题(StackOverFlowError)。这个需要根据实际情况而定。
jvm的一个实现,Hotspot
Hotspot是jvm中一个使用最广泛的实现。
方法区的实现
- 在jdk1.8之前方法区的采用永久代来实现
- 从jdk8开始使用元数据空间来实现方法区
这两个实现最重要的区别就是元数据空间并不在虚拟机中,而是使用本地内存。
堆的分类
Hotspot中堆被分为了新生代和老年代。更细一点划分新生代又可划分为Eden区和2个Survivor区(From Survivor和To Survivor)。平时我们所说的GC就发生在这。
-
Eden:新创建的对象存放在Eden区
-
From Survivor和To Survivor:保存新生代gc后还存活的对象。(使用复制算法,导致有一个Survivor空间浪费)Hotspot虚拟机新生代Eden和Survivor的大小比值为4:1,因为有两个Survivor,所以Eden:From Survivor:To Survivor比值为8:1:1。
-
老年代:对象存活时间比较长(经过多次新生代的垃圾收集,默认是15次)的对象则进入老年代。
当堆中分配的对象实例过多,且大部分对象都在使用,就会报内存溢出异常(OutOfMemoneyError)。
字符串常量存放位置,jdk1.7之前存在在永久代,1.7及之后存放在堆内存。
未完待续
网友评论