JVM内存结构
JVM是java代码的运行环境, 用来加载 .class
和jar文件 , 运行代码。
内存区域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
+------------------------------------------------------+
| |
| +-------------+ +---------------+ |
| | xxxA.class | | | |
| | xxxB.class | ----> | class loader | <--+ |
| | ... | | | | |
| +-------------+ +---------------+ | |
| v |
| +------------------------------------------------+ |
| | | |
| | +--------+ +------------+ +-------------+ | |
| | | Heap | | JVM Stacks | | pc Register | | |
| | +--------+ +------------+ +-------------+ | |
| | | |
| | +--------------+ +----------------------+ | |
| | | Method Area | | Native Method Stacks | | |
| | +--------------+ +----------------------+ | |
| | | |
| +--------------Run-Time Data Areas---------------+ |
| |
| ^ +-------------------------------+ |
| | | native method interface (JNI) | |
| | +-------------------------------+ |
| | ^ ^ |
| | | | |
| | | | |
| v v v |
| +------------------+ +--------------------------+ |
| | execution engine | | native method libraries | |
| +------------------+ +--------------------------+ |
| |
+------------------------------------------------------+
|
内存区域与运行关系
- 堆 Heap
圾回收的主要区域,又划分为新生代和老年代。
- 方法区 Method Area
存放常量池、静态变量、类信息、JIT编译后的代码等数据。
方法区是虚拟机规范中的概念,而永久代(PermGen)是HotSpot版的方法区。
HotSpot虚拟机从1.8开始取消了永久代,改为元空间(Metaspace)。
- 本地方法栈 Native Method Stacks
类似于虚拟机栈
- 虚拟机栈 Java Virtual Machine Stacks
每个线程都有,存放着局部变量表,返回值,栈帧等 。局部变量表: 基本数据类型与对象引用
栈帧:方法之间的调用顺序以栈的方式保存。
- 程序计数器 pc Register
pc (program counter)
每个线程都有,记录着线程当前运行到哪行代码
- 运行时常量池 Run-Time Constant Pool
属于方法区的一部分。
参考 Java运行时数据区
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
+------------------------------------------------+ +------------------------------------------------+
| | | |
| thread.1 | | thread.N |
| | | |
+------------------------------------------------+ +------------------------------------------------+
| pc Register | | pc Register |
| | | |
+------------------------------------------------+ +------------------------------------------------+
| | | |
| +-------------------+ +-------------------+ | | +-------------------+ +-------------------+ |
| | | | | | | | | | | |
| | JVM Stacks | | Native Method | | | | JVM Stacks | | Native Method | |
| | | | Stacks | | | | | | Stacks | |
| +-------------------+ +-------------------+ | | +-------------------+ +-------------------+ |
| | | | | | | | | | | |
| | | | | | | | | | | |
| | + ^ | | + ^ | | | | + ^ | | + ^ | |
| | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | |
| | v + | | v + | | | | v + | | v + | |
| | | | | | | | | | | |
| | +---------------+ | | +---------------+ | | | | +---------------+ | | +---------------+ | |
| | | stack frame | | | | stack frame | | | | | | stack frame | | | | stack frame | | |
| | +---------------+ | | +---------------+ | | | | +---------------+ | | +---------------+ | |
| | | ... | | | | ... | | | | | | ... | | | | ... | | |
| | +---------------+ | | +---------------+ | | | | +---------------+ | | +---------------+ | |
| | | stack frame | | | | stack frame | | | | | | stack frame | | | | stack frame | | |
| | +---------------+ | | +---------------+ | | | | +---------------+ | | +---------------+ | |
| | | | | | | | | | | |
| +-------------------+ +-------------------+ | | +-------------------+ +-------------------+ |
| | | |
| | | |
+------------------------------------------------+ +------------------------------------------------+
+---------all-threads-share------------------------------------+ +--------------------------------+
| | | |
| +---method-area--------------+ +---heap--------------+ | | |
| | | | | | | direct memory |
| | class(field, method, ...) | | | | | |
| | | | obj's | | | |
| +----------------------------+ | | | | |
| | Run Time Constant Pool | | | | | |
| +----------------------------+ +---------------------+ | | |
| | | |
+--------------------------------------------------------------+ +--------------------------------+
|
内存区域与线程关系
- 如何查看常量池,如何查看运行时常量池
javap可查看一个类的常量池。
运行时常量池可通过对内存dump,使用分析工具进行查看对比。
执行引擎
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
+----------Execution Engine----------+
| |
| +-------------+ |---------------+ |
| | | | | |
| | Interpreter | | JIT Compiler | |
| | | | | |
| +-------------+ +---------------+ |
| +------------------------+ |
| | | |
| | Garbage Collection | |
| | | |
| +------------------------+ |
| |
+------------------------------------+
|
- 解释器 Interpreter
将.class
代码按顺序解释执行。
相同Java代码在不同平台下编译后的.class
文件相同。
但在运行.class
代码时,还是要针对平台解释成不同的机器码的。
- JIT (Just In Time) Compiler
将部分热点代码直接编译成机器码,避免了反复通过Interpreter解释执行。
- 垃圾回收 Garbage Collection
收集移除无用的对象,释放内存。
JDK, JRE, JVM的区别
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
+-------------------------------------------------------------------------+
| JDK |
| |
| +---------------------------------------------------+ +-------------+ |
| | JRE | | | |
| | +----------------------+ | | | |
| | | | +----------------------- | | development | |
| | | JVM | | | | | tools | |
| | | | | set of libraries and | | | e.g : | |
| | | java virtual machine | | compiled class files | | | jstack | |
| | | | | | | | compiler | |
| | +----------------------+ +----------------------- | | | |
| | | | | |
| +---------------------------------------------------+ +-------------+ |
| |
| |
+-------------------------------------------------------------------------+
|
gc
gc(Garbage Collector) 垃圾回收器, 对内存中过期对象进行清理,为后续创建对象提供空间。
stw (stop the world) 指所有线程停止工作,垃圾回收器独掌大权,进行垃圾回收。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
+-----heap------------------------------------------+
| |
| +-------------+----+----+-----------------------+ |
| | | | | | |
| | eden | s0 | s1 | | |
| | | | | | |
| +-------------+----+----+-----------------------+ |
| young generation old generation |
| | | | |
| | <--- minor GC ---> | <--- major GC ---> | |
| | | | |
| | <-------------- full gc ---------------> | |
| |
+---------------------------------------------------+
|
垃圾回收主要是对位于堆中的对象进行回收,堆分成两部分:年轻代和老年代。
minor GC是对年轻代gc,major GC是对老年代gc。full GC == minor GC + major GC。
起初的垃圾回收,有年轻代和老年代的概念, 对年轻代gc频率高,对老年代gc频率低。
后来G1将新生代和老年代分成若干个region ,
而ZGC则没有新生代和老年代的概念。
回收逻辑
大部分对象刚创建的时候,JVM会放在Eden区域。
当Eden区域中的对象达到一定的数目的时候,就会进行Minor GC。
在完成垃圾回收后,存活的对象都会被送到某个Suvivor中,两个Suvivor区域总会有一个是空的(s0和s1交替)。
年轻代中经历过了多次垃圾回收,还活着的对象就会转移到年老代中。
当内存不足时,就会镜像full gc, 对整个堆进行垃圾回收。
垃圾回收器
- ZGC
- G1(Garbage-First) 并发
- 新生代 young generation
- Serial 串行
- ParNew 并行
- Parallel Scavenge 并行
- 老年代 old generation
- Serial Old 串行
- Parallel Old
- CMS 并发
Concurrent Mark Sweep (CMS) Collector
不同的垃圾回收器会有不同的参数类型配置
在ZGC以前的gc调优有两个方向: 吞吐量优先,响应时间优先。面临着鱼和熊掌不可兼得的困扰。
而ZGC是几乎无停顿的, 同时吞吐量也很高(比g1差点)。
该特性早在Azul JDK的C4 垃圾回收器就有,只不过用户习惯了oracle的jdk。
https://crowhawk.github.io/2017/08/15/jvm_3/
https://crowhawk.github.io/tags/#JVM
http://huzb.me/2019/02/21/CMS-G1%E5%92%8CZGC/
参数配置
在启动JVM虚拟机时,可以通过一些参数设置选用哪个垃圾回收器,
以及对该垃圾回收器,进行具体的配置。
比如: -XX:+UseSerialGC –XX:+UseG1GC
那么有哪些参数可以配置呢?
可以到oracle的文档中找
https://docs.oracle.com/en/java/javase/11/gctuning/
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/
文章作者
duansheli
上次更新
2019-12-25
(325c7b3)