GC相关
重要概念
stw(stop the world)
fullgc、老年代回收触发stw ; 垃圾回收时应用服务暂时不可用。
FootPrint gc需要的额外内存空间。
Throughtput(吞吐量)越高越好
堆
新生代(Eden)
存活代(Survivor)
老年代 (Tenured)
永久代(Permanent)(hotspot -> 堆外方法区)
常用垃圾回收算法
引用计数
为当前对象记录一个变量,每有一个对象引用,变量+1,当变量为0时代表可被清理。
问题:无法回收循环引用,算错无法重算。
Root Tracing
双色标记
三色标记
Root Tracing 每次都从根集合往下遍历集合,不可达的元素即为需要回收对象。
双色标记是指,遍历时上黑色,遍历结束回收白色对象。
问题:当遍历结束,白色对象被其他线程引用怎么办?
三色标记为双色标记的递归实现。
检查节点先上灰色,代表节点的引用节点还未检查,当全部检查完毕后,设置为黑色。
清理阶段,当白色节点被引用,会被设置为灰色节点,重新检查标记。
常用的垃圾回收器
垃圾回收器 | 特点和区别 | 总结 |
---|---|---|
Serial | 单线程垃圾回收器,用于较小的堆空间。在进行垃圾回收时暂停所有用户线程。适合于单核 CPU 或小型应用。 | 旧时代产物 |
Parallel | 多线程垃圾回收器,使用多个线程进行垃圾回收操作。适用于大型堆空间,利用多核处理器,可以更快地完成垃圾回收。在进行垃圾回收时暂停所有用户线程。 | 旧时代产物,更快回收垃圾,但stw |
CMS (Concurrent Mark-Sweep) | 并发垃圾回收器,尝试减少垃圾回收时的停顿时间。主要目标是减少停顿时间,允许应用程序的大部分工作在垃圾回收进行的同时继续运行。适用于需要短暂停顿时间和响应性能较高的应用。 | 适中回收速度,适中stw |
G1 (Garbage-First) | 分代垃圾回收器,尝试将堆空间分成多个区域(Region),适用于大型堆空间,可以更精确地控制暂停时间。不同于传统的分代回收,G1 的工作方式更灵活,更适合于需要可预测暂停时间的应用。 | 主流。更灵活控制速度、stw |
ZGC | 低停顿时间的垃圾回收器,致力于减少垃圾回收的停顿时间。适用于需要非常低的暂停时间(毫秒级别)的应用。与 G1 相比,ZGC 提供了更短的暂停时间,并且适用于大型堆空间。 | 最小的stw,内存溢出程序会挂 |
新生代一般采用标记复制算法-无stw(数据量小,复制不会产生stw)
老生代一般采用标记整理算法-有stw(清除时需要短暂暂停,防止并发情况出现引用改变)
常用jvm命令
jps java的进程查看工具
jstatd 启动远程访问
jstat --gcutil [pid] 查看各个区域[新生代老生代等区域信息]
jcmd pid VM.infos -all 查看
jmap dump ,分析占用信息(dump下来后进行jhat启动webserver查看)
jinfo 查看启动的vm参数
jstack pid 查看各个线程的堆栈信息
jconsle 默认监控面板
ClassLoader
BootStrapClassloader 加载jvm的相关类
ExtClassloader 加载jre/lib相关的扩展类
AppClassloader 加载应用类
CustomClassloader 自定义的classloader
双亲委派:
从下往上查找,查找到缓存直接返回。
查找不到,从上到下加载,放入缓存返回。
动态加载字节码:
引入javassist包
private static byte[] genClass(){
var pool = ClassPool.getDefault();
// 使用javassist创建动态class
var ctClass = pool.makeClass("greetings.Go");
var method = new CtMethod(CtClass.voidType, "greetings", new CtClass[]{}, ctClass);
method.setModifiers(Modifier.PUBLIC);
try {
method.setBody("{ System.out.println(\"Hi, greetings!\"); }");
ctClass.addMethod(method);
} catch (CannotCompileException e) {
e.printStackTrace();
}
try {
return ctClass.toBytecode();
} catch (IOException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
return null;
}
// 自定义loader
class BinLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (name == "greetings.Go") {
var bytes = genClass();
return defineClass("greetings.Go", bytes, 0, bytes.length);
}
return super.findClass(name);
}
}
@Test
public void test_gen() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 使用自定义loader动态加载class
var myloader = new BinLoader();
var goclazz= myloader.loadClass("greetings.Go");
var go = goclazz.getConstructor().newInstance();
go.getClass().getMethod("greetings").invoke(go);
}