• JVM笔记


    类加载机制

    加载流程

    loading:

    将类文件加载到内存,在堆中生成一个Class类对象供外部调用

    linking:

    验证(verification):验证,确保类信息没安全方面问题

    准备(preparation):赋默认值

    解析(resolution):符号引用变真实地址值

    initializing

    执行类构造器、赋初始值、执行静态代码块

    如果父类没有初始化,会先初始化父类

    对于类:load + 默认值 + 初始值

    对于对象:new + 申请内存 + 默认值 + 初始值

    编译器

    java是混合执行,即解释执行和编译执行。-Xint纯解释,-Xmixed混合执行,-Xcomp纯编译

    检测热点代码-XX:CompileThreshold=1000,超过这个值的调用混合模式会编译。JIT:Just In-Time Complier

    loading

    类加载器分类

    Bootstrap(启动类加载器,加载核心类)->Extenstion(扩展类加载器,加载扩展类)->Application(应用程序类加载器,自己写的代码)->Custom(自定义类加载器)

    双亲委派机制(代理模式)

    从下往上找是否被加载过,再从上往下加载。找不到同时也无法加载则报ClassNotFoundException

    是有类缓存

    为什么要用双亲委派?

    1.为了保证核心类库的安全,避免出现用户自定义java.lang.Object这样的情况。

    2.有一个缓存。

    代理模式即将指定类的加载交给其他类加载器。双亲委托机制是代理模式的一种

    自定义类加载器

    可以对class文件加密,然后用自己的类加载器加密后加载

    java.class.ClassLoader

    加载指定类,找到或生成对应的字节代码。即java.lang.Class的一个实例。还可以加载一些资源文件

    getParent()返回父类加载器

    loadClass(String name)加载名为name的类

    findClass(String name)查找名name类

    findLoadedClass(String name)查找已被加载过的类

    defineClass(String name,byte[] b,int off, int len)把字节数组b中的内容转换成java类,返回类实例

    resolveClass连接指定的java类

    自定义

    继承ClassLoader,重写findClass()方法

    1.首先检查请求类型是否已经装载,如果装载则返回

    2.委派给父类加载器,如果父类能够找到或装载完成则返回

    3.调用本类加载器的findClass方法,获取到则defineClass导入到方法区

    打破双亲委派机制

    重写loadClass即可打破

    线程上下文类加载器

    当前线程类加载器就是为了抛弃双亲委派加载链模式

    ThreadContextClassLoader可以实现基础类调用实现类代码,通过thread.setContextClassLoader指定。Thread.currentThead().getContextClassLoader()

    热部署,热启动:tomcat先加载再查找,为了保证安全不查找核心库。

    package at.guigu.study.jvm;
    
    import sun.misc.PerfCounter;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.lang.reflect.InvocationTargetException;
    
    public class CustomClassLoaderTest extends ClassLoader {
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
            CustomClassLoaderTest loaderTest = new CustomClassLoaderTest();
            Class<?> aClass = loaderTest.loadClass("at.guigu.study.jvm.CustomClassLoaderTest");
            aClass.getMethod("hello").invoke(aClass.newInstance(), new Object[]{});
            // 这里可以看出,新加载的类,并不会影响之前的。
            loaderTest.hello();
        }
    
        public String hello(){
            // class文件里是输出jvm,上面运行中先输出了jvm,再输出了hello
            System.out.println("hello");
            return "hello";
        }
    
        @Override
        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
            // 只改变了找类的逻辑,其它都没变
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        // 重写了loadClass方法,意味着java.lang包中类也会通过这个加载,所以要用extClassLoader加载。这里用app的父类加载器
                        Class<?> aClass = Thread.currentThread().getContextClassLoader().getParent().loadClass(name);
                        if (aClass != null) {
                            return aClass;
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }
    
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        c = findClass(name);
    
                        // this is the defining class loader; record the stats
                        PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            File file = new File("D:\\project\\java\\study_java\\file\\CustomClassLoaderTest.class");
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                int b = 0;
                while ((b = fileInputStream.read()) != -1) {
                    byteArrayOutputStream.write(b);
                }
                byte[] bytes = byteArrayOutputStream.toByteArray();
                byteArrayOutputStream.close();
                fileInputStream.close();
    
                return defineClass(name, bytes, 0, bytes.length);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return super.findClass(name);
        }
    }
    
    • 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
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    // class文件
    package at.guigu.study.jvm;
    
    public class CustomClassLoaderTest {
        public CustomClassLoaderTest() {
        }
    
        public String hello() {
            System.out.println("jvm");
            return "hello";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    linking

    verification验证是否符合jvm规范和安全

    perparation静态成员变量赋默认值

    resolution

    将类、方法、属性等符号引用解析为直接引用

    常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用

  • 相关阅读:
    Android 子线程为什么不能更新UI?
    操作系统MIT6.S081:P6->Page faults
    用Go+绘制爱心给心爱的她表白
    带你秒懂 SSR-服务端渲染
    一站式全链路压力测试平台Pone有哪些功能?
    技术应用:使用Spring Boot和Vue.js构建前后端分离的JWT认证应用
    Linux圈子里的“鲁大师“dmidecode-尚文网络xUP楠哥
    SSTI服务器模板注入漏洞
    数值类型表示二——定点和浮点格式
    【数据结构与算法】简单排序
  • 原文地址:https://blog.csdn.net/JokeOrSerious/article/details/127723916