yehao
发布于 2023-12-04 / 44 阅读
0
0

GC相关

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);
    }


评论