10.马士兵jvm

1.类编译加载和初始化

   1.loading(加载到内存)
   2.Linking
           1.verification(验证 文件格式 CAFE BABE)
           2.preparation(准备静态变量赋默认值,比如int0 String"")
           3.resolution(符号引用转为地址,可以直接访问)
   3.initializing(赋我们给的初值,调用静态代码块)

2.怎么知道我的类去哪个类加载器

   String.class.getClassLoader();

3.内存发生了什么?

CAFEBABE...二进制文件 load到内存,和生成的Class对象也进入内存
     我们通过Class一个大对象访问我们写的对象(metaspace中)(堆中)(由jvm生成)
    反射是通过 Class对象访问二进制 翻译为java代码,所以效率慢

4.类加载器(讲得很清晰)(不是继承关系,只是大小关系)(最好是写各个加载器的包的类,查看他是不是在这个加载器里面)

   Bootstrap启动类 加载 lib.rt.jar charset.jar由c++实现 返回为null
   Extension拓展类 加载拓展jar包 jre/lib/ext//*.jar 或 -Djava.ext.dirs指定
   App 加载classpath指定内容 (自己写的代码)
   Custom ClassLoader (自定义的加载器,自己指定加载什么)
    xx.class.getClassLoader().getClass().getClassLoader();//加载器的加载器不一定是他的父加载器
ClassLoader classLoader = MyClassLoader.class.getClassLoader();
    Class<? extends ClassLoader> aClass = classLoader.getClass();
    System.out.println(aClass.getName());//application

    ClassLoader classLoader1 = MyClassLoader.class.getClassLoader().getParent();
    Class<? extends ClassLoader> aClass1 = classLoader1.getClass();
    System.out.println(aClass1.getName());//extension

    ClassLoader classLoader2= MyClassLoader.class.getClassLoader().getParent().getParent();
    System.out.println(classLoader2);//bootstrapt

5.双亲委派机制(从子到父,从父到子的过程)(主要为了安全性,没有这个东西的话,如果自己写的String,会覆盖原来的代码String,这样写个发邮件把密码发我自己邮箱)

先从custom出发 如果cache有这个内容-没有->App
-没有->Ext--没有->Bootstrap--->返回--在他负责管理的jarclass类中找->Ext
--->App-->custom

图jvm10
请添加图片描述

6.父加载器(!!!不是类加载器的加载器,也不是类加载器的父类 ,只是成员变量的parent)

   xx.class.getClassLoader().getClass().getClassLoader(); //null不一定有
        xx.class.getClassLoader().getParent().getParent(); //父加载器 null  bootstrap

7.类加载器范围(加载的jar路径) Launcher类源码
图jvm11 验证路径
在这里插入图片描述

8.自定义类加载器 ClassLoader的loadClass方法源码(native方法是jvm里面的c++代码)

 //加载一个类到内存,然后得到他的名字
 //这个是使用App类加载器加载类
  Class classLoader = CustomLoader.class.getClassLoader().loadClass("top.jamsee.Cat");
    Cat cat = (Cat)classLoader.newInstance();
    cat.func1();
//什么时候需要加载一个类 spring动态代理,生成新class到内存中,热部署需要把class到内存中
//一个Loader类先继承ClassLoader重写findClass方法,

//使用,把Hello.class加载进来然后使用他的方法

public class CustomLoader extends ClassLoader  {
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        try {
            File f = new File("c:/test/", name.replaceAll(".", "/").concat(".class"));
            FileInputStream fis = new FileInputStream(f);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b = 0;
            while ((b = fis.read()) != 0) {
                baos.write(b);
            }

            byte[] bytes = baos.toByteArray();
            baos.close();
            fis.close();
            return defineClass(name, bytes, 0, bytes.length);


        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.findClass(name);
    }


    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
       ClassLoader l= new CustomLoader();
        Class cat = l.loadClass("top.jamsee.Cat");
        Cat cat1= (Cat)cat.newInstance();
    }

}
}

9.!!!(拓展)加密class(不想要被别人反编译,定义class的加密,这里使用对一个值异或再异或就会变成原来的一个值)
//下列代码只有加密过程,没有解密过程, ^ 异或2次变为原来的数据

    public class T007_MSBClassLoaderWithEncription extends ClassLoader {

    public static int seed = 0B10110110;

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        File f = new File("c:/test/", name.replace('.', '/').concat(".msbclass"));

        try {
            FileInputStream fis = new FileInputStream(f);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b = 0;

            while ((b=fis.read()) !=0) {
                baos.write(b ^ seed);
            }

            byte[] bytes = baos.toByteArray();
            baos.close();
            fis.close();//可以写的更加严谨

            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.findClass(name); //throws ClassNotFoundException
    }

    public static void main(String[] args) throws Exception {

        encFile("top.jamsee.Cat");

        ClassLoader l = new T007_MSBClassLoaderWithEncription();

        Class clazz = l.loadClass("top.jamsee.Cat");
        Cat h = (Cat) clazz.newInstance();
        h.func1();

        System.out.println(l.getClass().getClassLoader());
        System.out.println(l.getParent());

//
//        ClassLoader l1=Cat.class.getClassLoader();
//        Class aClass = l1.loadClass("top.jamsee.Cat");
//        Cat o = (Cat) aClass.newInstance();
//        o.func1();

    }
       //解密
    private static void encFile(String name) throws Exception {
        File f = new File("c:/test/", name.replace('.', '/').concat(".class"));
        FileInputStream fis = new FileInputStream(f);

        FileOutputStream fos = new FileOutputStream(new File("c:/test/"+name.replace(".","/").concat(".msbclass")));
        int b = 0;
        while((b = fis.read()) != -1) {
            fos.write(b ^ seed);
        }

        fis.close();
        fos.close();
    }
}

10.编译(jvm默认使用混合模式)

  1.解释器(启动慢) bytecode intepreter  是变class代码
  2.JIP just in time compiler编译器(启动快),有些代码需要编译为本地exe代码
  3.混合模式(默认使用,使用jvm参数可以指定 -Xmixed混合 启动快,还能及时编译 -Xint解释模式(变本地代码),-Xcomp纯编译模式): 
        1. 混合使用解释器和多次使用的代码
        2.起始阶段用解释执行
        3.热点代码检测 多次调用的方法(方法计数器)和循环(循环计数器) 进行

编译时的代码

   例子:  写多个个10万次的循环调用一个方法,run->edit config 指定jvm参数 -Xint纯解释()  -Xint纯编译(更快)

11.懒加载(了解) lazyinializing 懒初始化 (按需加载 比如new 出来先加载 final不用加载但是可以取出来)

  1.jvm没有规定何时把类加载进来,由你自己指定,load到内存
  2.但是严格规定什么时候什么时候必须初始化类
       1.new getstatic putstatic invokestatic指令,final变量除外(final不用初始化,直接可以取出)
       2.反射
       3.初始化子类,父类必须首先初始化
       4. 动态语言(这个语言)支持 invoke.MethodHandle的结果为 REF_ getstatic Ref_putstatic REF_invokestatic必须初始化
例子:
   class aa{
     main(){
         P p;//类不会打印静态代码块的内容
         P p1=new P(); //会打印,因为new 关键字在懒加载中
         sout(p1.i);//可以打印,final关键字,不用加载,但是直接被转化为内存地址,取出值
      
     }
     public static class P{
             final static int i=8;
             static{
     		sout("aaa");
              }

     }


   }
  1. 复习
 1.ClassLoader源码 findCache-->parent.loadClass-->findClass()
   2.自定义类加载器  extends ClassLoader--->overwrite findClass()-->
        defineClass(byte[]-->Class clazz)字节数组转化为Class对象
3.加密
4.混合执行

13.JVM检测热点代码参数

  -XX:CompileThreshold=10000

14.(了解,面试 直接找下一家)双亲委派机制是可以打破的

  1.重写ClassLoaderloadClass()
  2.何时打破 jdk1.2 ThreadContextClassLoader
          通过thread.setContextClassLoader指定
 3.热启动(常用)tomcat里面有自己实现classloader 
          例如 tomcat 有 多个webapplication, 分别在里面可以放同名的类,(已经打破双亲委派机制)
           loadClass两次,第二次不会加载,因为在缓存中

代码图12 121
请添加图片描述
请添加图片描述

15.linking

  1.verification 验证文件是否符合jvm规范
  2.preparation 静态成员赋默认值(0 1 null)
  3.resolution是否进行解析 将类 方法属性等符号引用解析为直接引用(常量池的符号引用解析为指针 偏移量内存地址的直接引用)(符号引用--->指针,地址)

16.initializing 调用类初始化代码 给静态成员赋初始值
面试题:(一般不这样写程序,直接static{}赋初值)

   class T{
         public static int count=2;  //(2) count=0
         T t=new T();                     // (3) count=1
        private T(){
	count++;
         }

   }

  main(){
      sout(T.count);//3  linking( )--->initializing (1)
 
   }

下面是先new对象的情况

    class T{
      
         T t=new T();                     // (1)preparate  count=0 ---> count=1
           public static int count=2;  // (2)  initializing count=2
        private T(){
	count++;
         }

   }
  main(){
      sout(T.count);//2  linking(preparate )--->initializing
 
   }

//load—>默认值—>初始值
//对象 new–申请内存–默认值—初始值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值