目录
运行时数据区域
JVM在运行时会把其管理的内存分为如下数据区域。分别是: 方法区、堆、 虚拟机栈、本地方法栈、程序计数器。
方法区、堆、都是所有线程共享,在JVM启动时创建,在JVM停止时销毁。
虚拟机栈、本地方法栈、程序计数器。 是线程私有的,随线程的创建而创建,随线程的结束而死亡。
-----------------------------------------------------------------------------读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明
程序计数器(Program Counter Register)
程序计数器
是一块较小的内存空间,如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址
; 如果正在执行的是本地(Native)方法,这个计数器值则应为空(Undefined)。
此内存区域是唯一一个在《Java虚拟机规范》中没有规定任何OutOfMemoryError
情况的区域。
-----------------------------------------------------------------------------读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明
程序计数器有两个作用:
- 字节码解释器通过改变程序计数器来一次读取指令,从而实现代码的 流程控制 ,比如我们常见的顺序、循环、选择、异常处理等。
- 在多线程的情况下,程序计数器用来记录当前线程执行的位置,当 线程切换 回来的时候仍然可以知道该线程上次执行到了哪里
------------------------------------------------------------------------------基于网络博客总结
虚拟机栈(Java Virtual Machine Stack)
虚拟机栈描述的是
Java方法执行的线程内存模型
。
每个方法被执行的时候JVM都会同步创建一个栈帧(Stack Frame)
。每一个方法被调用直至执行完毕的过程就对应着一个栈帧在虚拟机栈中从入栈
到出栈
的过程。
经常有人把Java内存区域笼统地划分为
堆内存(Heap)
和栈内存(Stack)
,而“栈”通常就是指这里讲的虚拟机栈,或者更多的情况下只是指虚拟机栈中局部变量表
部分。
[Q&A] 局部变量表存储了啥?
- 基本数据类型(char、short、int、long、float、double、boolean、byte)
- reference类型 (对象引用)
- returnAddress类型(指向了一条字节码指令的地址)
-----------------------------------------------------------------------------读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明
栈帧(Stack Frame)
图 [Ref] JVM内存模型详解(1.7与1.8的区别)
本地方法栈(Native Method Stacks)
本地方法栈结构上和Java虚拟机栈一样,发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是为虚拟机使用到的本地方法服务。 运行本地方法时也会创建栈帧,同样栈帧里也有局部变量表、操作数栈、动态链接和方法返回地址等,在本地方法执行结束后栈帧也会出栈并释放内存资源,也会发生OutOfMemoryError
。
直接内存(Direct Memory)
直接内存(Direct Memory)不是JVM运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。 例如:计算机内存8G。JVM分配了2G,那么6G就是直接内存.
Java堆(Java Heap)
[Q&A] 堆存储了啥?
《Java虚拟机规范》原文:The heap is the runtime data area from which memory forall class instances
andarrays
is allocated。
[Q&A] 堆物理内存如何分配?
根据《Java虚拟机规范》的规定,Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的,这点就像我们用磁盘空间去存储文件一样,并不要求每个文件都连续存放。但对于大对象(典型的如数组对象),多数虚拟机实现出于实现简单、存储高效的考虑,很可能会要求连续的内存空间。
[Q&A] 什么是大对象?
所谓大对象是指需要大量连续存储空间的对象
,最常见的一种大对象就是大数组
。
[Q&A] 什么是TLAB?
如果从分配内存的角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB),以提升对象分配时的效率。
-----------------------------------------------------------------------------读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明
[Q&A] 堆为啥又叫GC堆?
Java堆是垃圾收集器管理的内存区域,因此一些资料中它也被称作“GC堆”
。
[Q&A] Java堆细分的目的是啥?
将Java堆细分的目的只是为了更好地回收内存
,或者更快地分配内存
。
[Q&A] 非经典分代理论收集器?
HotSpot里面也出现了不采用分代设计的新垃圾收集器,如(以G1收集器
的出现为分界)
[Q&A] 经典分代理论收集器?
由于现代垃圾收集器
大部分都是基于分代收集理论
设计的,所以Java堆中经常会出现 “新生代” “老年代” “永久代” “Eden空间” “From Survivor空间” “To Survivor空间”等名词,这些区域划分仅仅是一部分垃圾收集器的共同特性或者说设计风格而已,而非某个Java虚拟机具体实现的固有内存布局,更不是《Java虚拟机规范》里对Java堆的进一步细致划分。
新生代(Young Generation)
几乎所有新生成的对象首先都是放在新生代的。
老年代(Old Generation)
可以认为年老代中存放的都是一些生命周期较长的对象
。
1、当对象在 Survivor 区躲过一次 GC 的话,其对象年龄便会加1
,默认在新生代中经历了15
次垃圾回收后仍然存活的对象,就会被放到老年代中;可以通过 -XX:MaxTenuringThreshold 改变次数。
2、对象大小超过指定大小直接进入老年代。可以通过 -XX:PretenureSizeThreshold 改变规定大小。
永久代(Permanent Generation)
1、永久代是jdk1.6以前对方法区的实现。
3、永久代在 Java SE8 特性中已经被移除了,取而代之的是元空间(MetaSpace),因此也不会再出现java.lang.OutOfMemoryError: PermGen error
的错误了。
默认 Eden : s0 : s1是 = 8 : 1 : 1 ,也可以通过-XX:SurvivorRatio
来配置
默认 老年代 : 新生代 = 2 : 1,也可以通过-XX:NewRatio
来配置
java8取消了永久代,采用了元空间(Metaspace)
方法区(Method Area)
[Q&A] 方法区都存什么?
存储已被虚拟机加载的 类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
[Q&A] 在JDK 8以前,HotSpot虚拟机设计团队为啥使用永久代来实现方法区?
希望使得HotSpot的垃圾收集器能够像管理Java堆一样管理这部分内存,省去专门为方法区编写内存管理代码的工作。
[Q&A] 为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢?
1、在 JDK8,合并 HotSpot 和 JRockit 的代码时, JRockit 从来没有一个叫永久代的东西, 故舍弃了HotSpot的永久代。
2、元空间里面存放的是类的元数据,这样加载多少类的元数据就不由MaxPermSize
控制了, 而由系统的实际可用空间来控制,这样能加载的类就更多了。
[Q&A] 取代永久代的就是元空间。它和永久代有什么不同的?
永久代是 堆 的一部分,和新生代,老年代地址是连续的;元空间属于本地内存;
[Q&A] 元空间替换方法区过程?
当Oracle收购BEA获得了JRockit
的所有权后,准备把JRockit中的优秀功能,譬如Java Mission Control管理工具,移植到HotSpot虚拟机时,但因为两者对方法区实现的差异而面临诸多困难。考虑到HotSpot未来的发展,在JDK 6
的时候HotSpot开发团队就有放弃永久代,逐步改为采用本地内存(Native Memory)
来实现方法区的计划了,到了JDK 7
的HotSpot,已经把原本放在永久代的 字符串常量池、静态变量等移出,而到了JDK 8
,终于完全废弃了永久代的概念,改用与JRockit、J9一样在本地内存中实现的元空间(Meta-space)
来代替,把JDK 7中永久代还剩余的内容(主要是类型信息)全部移到元空间中。
-----------------------------------------------------------------------------读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明
[Q&A] 相对于JDK1.6, Java1.8 HotSpots取消了永久代,那么是不是也就没有方法区了呢?
不是,方法区
是一个规范,jdk1.8之前方法区通过永久代
实现,jdk1.8之后通过元数据区
实现
Further Reading : 方法区到底是什么鬼.
-----------------------------------------------------------------------------以上自己整理,谨慎参考