一、JVM类加载机制——自定义类加载器
二、JVM——对象内存分配机制
三、JVM内存模型
四、JVM垃圾收集算法和垃圾收集器
五、CMS垃圾回收器——三色标记算法
六、G1垃圾收集器
七、JVM调优实战——基本命令使用
八、JVM调优实战——arthas使用
九、大流量电商系统JVM调优案例
一、JVM内存总共分为5个部分,下面我们就从这5个部分结合代码分别进行介绍:
package com.ysy.内存模型;
import java.util.ArrayList;
/**
* @author shanyangyang
* @date 2020/7/7
*/
public class MemTest {
public static ArrayList<Integer> arrayList = new ArrayList<>();
public String str = "abc";
private final Integer num = 1;
public static void main(String[] args) {
int a = 1;
int b = 2;
MemTest test = new MemTest();
int c = test.add(a, b);
System.out.println(c);
}
public int add(int a, int b) {
return a + b;
}
}
类装载子系统将编译后的MemTest.class文件装载入JVM虚拟机中。
二、JVM内存参数设置
springboot的JVM设置参数直接加在tomcat启动的catalina.sh文件里。
关于元空间的参数配置:-XX:MetaspaceSize=N和-XX:MaxMetaspaceSize=N
-XX:MetaspaceSize:指元空间触发fullgc的初始阀值,默认21M。可以弹性变化。
一般建议将MetaspaceSize和MaxMetaspaceSize的值设置一样大,对于8G物理内存,建议将这两个值设置为256M。
大流量电商系统JVM调优案例
三、StackOoverflow示例
-Xss设置为128K,很快方法就会报错,栈溢出。
-Xss设置的越小,说明一个线程栈里面可以分配的栈帧就越少,但是JVM整体来说开启的线程数会越多。
package com.ysy.stackoverflower示例;
/**
* @author shanyangyang
* @date 2020/7/18
* 设置栈大小为 -Xss128k
*/
public class StackOverFlower {
static int count = 0;
static void redo() {
count++;
redo();
}
public static void main(String[] args) {
try {
redo();
} catch (StackOverflowError stackOverflowError) {
System.out.println(count);
}
}
}
四、JVM内存模块介绍
# 1、程序计数器
最小的一块内存区域,它是线程独享的,指向当前线程执行的字节码;字节码解释器工作时,通过改变程序计数器的值来取出下一条需要执行的命令。
2、堆(JVM垃圾回收器)
是最大的一块内存区域,它是所有线程共享的;几乎所有的对象实例都存放在该区域。
我们平时在java中经常提及的jvm垃圾回收,主要涉及的就是这块的内存;因此我们“堆”也被称为“GC堆”。
根据垃圾回收的原则:我们又把堆分为老年代和年轻代,将年轻代进一步的划分为eden区域、from survive和to survive区域;
堆大小 = 老年代+年轻代
2.1 年轻代
程序创建对象都是从年轻代开始的;jvm只会拿出eden和一块survive区域出来给对象分配地址,也就是说总有一块survive区域是空着的。
2.1.1 未进行GC时,对象分布在eden和from survive区域中,to survive区域是空的;
2.1.2 紧接着发生GC,Eden区域中的对象都会被复制到to survive区域中,而form survive区域中的对象会根据对象年龄来决定去向;
2.1.3 -XX:MaxTenringThreshold设置一个值,大于这个值的对象移动到老年代中,小于这个值的对象移动到to survive区域中;经过这次GC之后,Eden区域和form survive区域会空出来;
2.1.4 此时to survive和from survive完成了角色更替;
上面描述的就是一次minor GC的过程;如果to survive也被填满了,那就将to survive中所有的对象移动到老年代中;
移动就是复制,因为年轻代使用的复制算法
2.2 老年代
用于存放经过多次minor GC依然活着的对象(老兵不死,只是凋零),对象不死,只是进入了老年代中;
老年代中的垃圾回收为FUll GC。
Full GC采用的是标记-清除算法。不同的垃圾回收器使用的算法不尽相同。
3、方法区-元空间
方法区也被称为永久代,用于存放虚拟机加载的类信息、静态变量、运行时常量池,是各个线程共享的区域。
运行时常量池是方法区的一部分,用于存放编译器产生的各种符号引用。
4、虚拟机栈
和程序计数器一样,也是线程私有的,它的生命周期与线程相同。每一个方法被调用直至执行结束的过程,都对应着一个栈帧在虚拟中从入栈到出栈的过程。
5、本地方法栈
与虚拟机栈基本类似,也是私有的,区别在于虚拟机栈为虚拟机执行java程序服务,而本地方法栈为虚拟机使用到的native方法服务。