JVM内存结构
原文:https://www.cnblogs.com/hexinwei1/p/9406239.html 1、程序计数器 PC Register 每个线程都有一个程序计算器,就是一个指针,指向方法区中的方法字节码(下一个将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。
2、本地方法栈?Native Method Stack Native Method Stack中登记native方法,在Execution Engine执行时加载native libraies 本地方法栈与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务 3、方法区??Method Area 用于存储虚拟机加载的:静态变量+常量+类信息+运行时常量池?(类信息:类的版本、字段、方法、接口、构造函数等描述信息 ) 默认最小值为16MB,最大值为64MB,可以通过 对于习惯在HotSpot 虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”(Permanent Generation),本质上两者并不等价,仅仅是因为HotSpot 虚拟机的设计团队选择把GC 分代收集扩展至方法区,或者说使用永久代来实现方法区而已。对于其他虚拟机(如BEA JRockit、IBM J9 等)来说是不存在永久代的概念的。即使是HotSpot 虚拟机本身,根据官方发布的路线图信息,现在也有放弃永久代并“搬家”至Native Memory 来实现方法区的规划了。Java 虚拟机规范对这个区域的限制非常宽松,除了和Java 堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是有必要的。在Sun 公司的BUG 列表中,曾出现过的若干个严重的BUG 就是由于低版本的HotSpot 虚拟机对此区域未完全回收而导致内存泄漏。根据Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常。 4、栈?JVM Stack 编译器可知的各种基本数据类型( 栈是java 方法执行的内存模型: 每个方法被执行的时候 都会创建一个“栈帧”用于存储局部变量表(包括参数)、操作栈、方法出口等信息。 每个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。 (局部变量表:存放了编译器可知的各种基本数据类型( 其中64位长度的long和double类型的数据会占用2个局部变量的空间,其余数据类型只占1个。 局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量是完全确定的,在运行期间栈帧不会改变局部变量表的大小空间) 栈的生命期是跟随线程的生命期,线程创建时创建,线程结束栈内存也就释放,是线程私有的。 5、堆??Java Heap 所有的对象实例以及数组都要在堆上分配,此内存区域的唯一目的就是存放对象实例 堆是Java?虚拟机所管理的内存中最大的一块。Java?堆是被所有线程共享的一块内存区域,在虚拟机启动时创建 堆是理解Java GC机制最重要的区域,没有之一 结构:新生代(Eden区+2个Survivor区)? 老年代? ?永久代(HotSpot有) 新生代:新创建的对象——>Eden区? GC之后,存活的对象由Eden区?Survivor区0进入Survivor区1? ? 再次GC,存活的对象由Eden区?Survivor区1进入Survivor区0? (Eden:s0:s1 = 8:1:1) 老年代:对象如果在新生代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来),则会被复制到老年代 如果新创建对象比较大(比如长字符串或大数组),新生代空间不足,则大对象会直接分配到老年代上(大对象可能触发提前GC,应少用,更应避免使用短命的大对象) 老年代的空间一般比新生代大,能存放更多的对象,在老年代上发生的GC次数也比年轻代少 (新生代:老年代 = 1:2) 永久代:可以简单理解为方法区(本质上两者并不等价) 如上文所说:对于习惯在HotSpot 虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”,本质上两者并不等价 仅仅是因为HotSpot 虚拟机的设计团队选择把GC 分代收集扩展至方法区,或者说使用永久代来实现方法区而已 对于其他虚拟机(如BEA JRockit、IBM J9 等)来说是不存在永久代的概念的 即使是HotSpot 虚拟机本身,根据官方发布的路线图信息,现在也有放弃永久代并“搬家”至Native Memory 来实现方法区的规划了 Jdk1.6及之前:常量池分配在永久代 Jdk1.7:有,但已经逐步“去永久代” Jdk1.8及之后:没有永久代(java.lang.OutOfMemoryError: PermGen space,这种错误将不会出现在JDK1.8中) 6、直接内存? Direct Memor 直接内存并不是JVM管理的内存,可以这样理解,直接内存,就是JVM以外的机器内存,比如,你有4G的内存,JVM占用了1G,则其余的3G就是直接内存 JDK中有一种基于通道(Channel)和缓冲区(Buffer)的内存分配方式,将由C语言实现的native函数库分配在直接内存中,用存储在JVM堆中的DirectByteBuffer来引用 由于直接内存受到本机器内存的限制,所以也可能出现OutOfMemoryError的异常。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |