1、定义
JDK:Java Develop Kit,java开发工具;
JRE:Java Runtime Environment,java运行时环境;
JVM:Java Virtual Machine,java虚拟机;实现java语言跨平台的特点;
JDK包含 JRE 包含JVM;
一次编译,到处运行:java文件javac编译为.class字节码文件,JVM负责将字节码文件翻译为对应下载JDK时选择的Windows/Linux下的机器码(可通过javap查看)然后运行。
2、JVM详解
java虚拟机包含了:栈、堆、方法区(java1.8后更名为元空间)、程序计数器、本地方法栈;
-
栈Stack:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。按FIFO先进后出,每个方法结束时释放资源。
-
堆Heap:是Java虚拟机中内存最大的一块,是被所有线程共享的。存储程序运行中生成的对象实例,也是垃圾回收性能调优的重点。
-
方法区Method Area:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
-
程序计数器:每个线程即一个栈,栈中有多个方法即多个栈帧。每个线程栈帧都有自己的程序计数器,即记录程序执行的位置。
-
本地方法栈:
3、JVM性能调优
当栈、堆超出分配的空间时,即会抛出对应的异常:StackOverflowError、OutOfMemoryError;
当堆的老年代满了之后会执行full gc,此时会STW(stop the work),即暂停所有运行时线程专心执行垃圾回收
因此java性能调优的关键即是:防止full gc
堆空间的一般结构:
-
新生代:eden --> s0 --> s1 --> 老年代 tenured
-
对象实例首先进入eden,当对象大小 < s0的一半大小则进行minio gc进入s0。否则直接进入老年代
-
eden:s0:s1的空间分配比例一般为8:1:1;新生代:老年代一般为1:2;但具体情况具体分析;
-
比如秒杀等高并发场景,若每秒数据为60M,假设这些数据一分钟左右都能销毁;此时怎样分配空间尽可能避免full gc;
-
若eden:s0:s1为 800M:100M:100M,老年代2G,则eden满了之后进行minio gc 发现60M>100M/2,此时数据将直接进入老年代,造成频繁full gc;
-
若eden:s0:s1为 1.6G:200M:200M,老年代1G,则数据在第一次进入s0后下次即可销毁,可有效防止full gc