本文主要以jdk8为基础,简单陈述一下JMM,下图,是我根据jvms8简单画的一个图。
下面详细介绍一下java的运行时数据区:
1.The pc Registe(程序计数器)
jvm支持多个线程同时运行,每一个jvm线程都有自己的程序计数器。值得注意的是pc中存放的是指令的位置,如果将要执行的方法是被native修饰的,那么pc是undefined。线程从pc中获取位置,然后找到该位置对应的指令,然后执行指令。pc的空间是足够大的,不会溢出(The JavaVirtual Machine's pc register is wide enough to hold a returnAddress or a nativepointer on the specific platform.)。
2.Java Virtual Machine Stacks
jvm栈是线程独有的,随着线程的创建而创建。 jvm栈是由多个frame(栈帧)组成的。每个方法对应一个栈帧,如果调用A方法,会在当前线程的栈内创建一个A方法的栈帧,当方法执行结束,该栈帧就消亡了,如果再次调用A方法,又会重新创建一个栈帧。
frame的结构如下:
- Local Variables:局部变量表,存方法参数和局部变量的。如果是非静态方法,0位的值是this,如下图:
- Operand Stacks:操作数栈,先进后出,后进先出的原则。
- Dynamic Linking:将符号引用解析为直接引用。(Dynamic linking translates these symbolicmethod references into concrete method references, loading classes as necessary toresolve as-yet-undefined symbols, and translates variable accesses into appropriate offsets in storage structures associated with the run-time location of these variables.)
- Normal Method Invocation Completion/Abrupt Method Invocation Completion:方法的返回,一种是方法正常结束,另外一种就是方法抛出异常了。详细的可以参考jvms8的2.6.4和2.6.5两节。
3.Heap(堆)
堆是被所有JVM线程共享的,GC回收的区域。常用的GC有十种:Serial、SerialOld、ParNew、CMS、ParallelScavenge、ParallelOld、G1、ZGC、Epsilon、Shenandoah。在G1之前,堆无论是在逻辑上还是物理上都是分新生代和老年代的。从G1开始,逻辑分代,物理就不分代了。G1之后,逻辑和物理都不分代了。jdk8默认的GC是PS(ParallelScavenge)+PO(ParallelOld),所以jdk8的时候堆是分新生代和老年代,其中新生代分为eden区、from(s0/s1)区、to(s1/s2)区。
4.Method Area(方法区)
方法区是被所有JVM线程共享的。在jdk8之后,方法区只是逻辑上属于堆,实际上是内存上一块可能不连续的区域。
针对HotSpot来说,在jdk8之前,方法区是通过PermSpace(永久代)实现的。jdk8以及8之后,方法区是Metaspace(元空间)实现的。下图是关于永久代和元空间的一点区别总结。
5.Run-Time Constant Pool(运行时常量池)
运行时常量池是方法区的一部分。是在JVM完成类加载之后,将类文件的常量存储在方法区。(jvms:Each run-time constant pool is allocated from the Java Virtual Machine's methodarea . The run-time constant pool for a class or interface is constructed when the class or interface is created by the Java Virtual Machine.)
6.Native Method Stacks(本地方法栈)
本地方法栈是用来支持不是用java语言写的方法。
简述一下对象的分配过程:
创建对象,先栈上分配,如果栈上分配得下, 那么压栈、出栈,对象结束。
如果栈上分配不下,这个时候就要考虑对象的大小。如果对象很大,那么直接进入老年代,等着FGC。如果对象不大,那么先考虑在TLAB分配,如果分配不下,那么Eden区。(TLAB也是Eden区的一部分,线程在eden区的一块独享空间)
Eden区满了,触发GC,对象可能进入s1区或者被回收,如果进入s1,再经历一次GC后,可能进入s2或者被回收。每次GC回收的是Eden区和s1/s2中的某一个区。经过多次GC未被回收的,达到一定年龄后,会进入老年代,老年代满了,触发FGC,结束。