zoukankan      html  css  js  c++  java
  • JVM1

    虚拟机是有规范的,HotSpotsun公司也就是现在的oracle公司提供的,虚拟机并不是只有oracle有,IBM也有虚拟机,虚拟机是有规范的, 只要遵循这个规范就可以自己造虚拟机。虚拟机也有商用的,收费很高。Oracle是免费的虚拟机。Openjdk是基于jdk的开源实现,open是开源的意思。

    HotSpotoracle的,是使用的很广泛的。

    Java代码中,类型的加载,链接,初始化都是在程序运行期间runtime完成的(其他的一些语言是编译期间完成的)。类型是定义的一个类、接口、枚举,不是对象。

    动态代理是类型在运行期间动态的生成出来,在编译期间没有的。

    Java是静态语言,但是也有很多动态的特性。

    加载:class文件从磁盘到内存

    连接:类与类的关系确定好,字节码的验证校验。字节码有问题虚拟机就不会去执行。字节码文件是可以人为操纵的。

    初始化:类的静态变量赋值。都是在运行期间完成的,不是编译期间。

    类加载器:每一个类型(类)会被纳入jvm管辖范围中。加载类的工具。

    虚拟机就是一个进程,进程在某些情况下就会停掉:

    1. 程序执行了System.exit()
    2. 程序正常结束
    3. 执行过程中遇到了异常
    4. 操作系统层面出现错误导致虚拟机进程结束

    符号引用就是字符串,写的时候,直接引用就是去找相应的地址

    类的卸载:类的信息从内存移除。

    加载:类加载到内存,.class文件二进制数据读入到内存,放入到方法区中,然后在内存创建一个Class对象,虚拟机规范并没有规定Class对象放在哪里,OracleHotSpot虚拟机将其放在了方法区中(没有放到堆区),Class对象封装类在方法区的数据结构。所有的实例都会对应一份Class对象。所以反射要使用Class对象。

    验证:验证类的正确性

    准备:静态变量赋予初始值,分配相应的空间大小。

    解析:符号引用转换为直接引用

    初始化:赋予正确的初始值

    加载链接初始化加载到内存、校验,赋予默认值、正确值,符号引用转换

    加载class文件的方式:

    1. 磁盘直接加载,位于classpath类路径下
    2. 网络下载.class文件
    3. Zip,jar文件加载.class文件
    4. 数据库提取.class文件(使用的少)
    5. Java源文件动态编译为.class文件(动态代理)。运行期生成,编译时没有。jsp文件转换成class文件。

    Java对类的使用方式:

    1. 主动使用
    2. 被动使用

    类或接口必须首次主动使用初始化(初始化就会执行里面的static代码块)。不首次主动使用也会加载,只是不初始化

     

    JVM规范允许加载器预料某个类将要使用时候预先加载它,如果预先加载中遇到了class文件错误,类加载器要在首次主动使用这个类时候报告错误。入股这个类一直没有首次使用,就一直不报错

     

    主动使用7种:

     

    1. 创建实例
    2. 访问(读写)类的静态变量。调用类的静态方法
    3. 反射
    4. 初始化类的子类(初始化之类时候父类也是主动使用,也会初始化,爷爷类也会初始化)
    5. 被标记为启动类的类(main函数了类,入口类)

     

    其他使用类的方式都是被动使用,都不会导致类的初始化。有可能导致类的加载和链接

    调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。

     

    先让父类加载器加载,加载不了在自己加载,是为了安全

    表面看是一种继承关系,实际上是一种包含关系。

    public class 额鹅鹅鹅 {
        public static void main(String[] args) {
            System.out.println(Child.p);
        }
    }
    
    class Parent{
        static String p = "parent";
        static {
            System.out.println("parent static");
        }
    }
    
    class Child extends Parent{
        static String c = "Child";
        static {
            System.out.println("Child static");
        }
    }
    /*
     System.out.println(Child.c)
         parent static
        Child static
        Child
        使用子类的静态属性,是对子类的主动使用,父类的静态代码块执行,子类的静态代码块会执行。
     
     System.out.println(Child.p)
         parent static
        parent
         使用父类的静态属性,不是对子类的主动使用,父类的静态代码块执行,子类的静态代码块不会执行。
     */

     -XX:+TraceClassLoading,追踪类的加载信息

     -XX:+TraceClassUnloading,追踪类的卸载信息

    -XX:+<option>:开启option选项

    -XX:-<option>:关闭option选项

    -XX:<option>=value:设置option选项值

     

    Jvm的参数有上千个,

     

    如何在windows平台下使用hsdisjitwatch查看JIT后的汇编码

    https://www.cnblogs.com/stevenczp/p/7975776.html

    package com.ssss;
    class A  {
        static final String c = "Child";//final是常量,编译阶段,常量放在调用这个常量的方法所在的类的常量池中。就是TT类的常量池中。
        //TT类并没有直接引用A类,因此使用A.c这个常量的时候,不会触发A类的初始化,因此Child static不会打印。
        //因为是在TT类的常量池中,因此TT类和A类没有关系了。甚至将A类的class文件删除都可以。(不能删源文件,否则就不能编译了)
        volatile int s = 1;
        static {
            System.out.println("Child static");
        }
        public synchronized int j() {
            return s++;
        }
    }/*
     Child
     */
                                    // javap 查看java编译器为我们生成的字节码汇编代码。
    /*
    C:UsersAdminDesktop图片111>javap -c A.class
    class ssss.A {
      static final java.lang.String c;//属性
    
      static {};//静态
        Code:
           0: getstatic     #13    // Field java/lang/System.out:Ljava/io/PrintStream :System.out.println
           3: ldc           #19    // String Child static
           5: invokevirtual #21    // Method java/io/PrintStream.println:(Ljava/lang/String;)V :System.out.println
           8: return
    
      ssss.A();//方法
        Code:
           0: aload_0
           1: invokespecial #30    // Method java/lang/Object."<init>":()V
           4: return
    }
    
    C:UsersAdminDesktop图片111>javap -c TT.class
    Compiled from "TT.java"
    public class ssss.TT {
      public ssss.TT();
        Code:
           0: aload_0
           1: invokespecial #8      // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]);
        Code:
           0: getstatic     #16      // Field java/lang/System.out:Ljava/io/PrintStream :System.out.println
           3: ldc           #22      // String Child ,A.c已经是Child了,编译时候就已经是Child了。ldc将int,float,String推到栈顶。
           5: invokevirtual #24      // Method java/io/PrintStream.println:(Ljava/lang/String;)V :System.out.println
           8: return
    }
    */
    public class TT {
        public static void main(String[] args) {
            System.out.println(A.c);
        }
    }
    class abc {
        //常量final UUID.randomUUID()不是编译期间可以确定值,那么编译时候就不会把str的值放入
        //DDD类的常量池中,运行时候,就会主动使用abc类,导致abc类的初始化。否则abc类是不会初始化的(abc的static代码块就不会执行)。
        public static final String str = UUID.randomUUID().toString();
        static {
            System.out.println("static");
        }
    }
    
    public class DDD{
        public static void main(String[] args) {
            System.out.println(abc.str);
        }
    }
    class abc {
        static {
            System.out.println("static abc");
        }
    }
    
    public class DDD{
        public static void main(String[] args) {
            abc a = new abc();//静态代码块执行
            System.out.println(a.getClass());//class com.ssss.abc
            System.out.println(a.getClass().getSuperclass());//class java.lang.Object
            
            abc[] ss = new abc[1];//不会执行静态代码块,数组不是主动使用,
            System.out.println(ss.getClass());//class [Lcom.ssss.abc;
            System.out.println(ss.getClass().getSuperclass());//class java.lang.Object
            
            int[] i = new int[1];//,不是主动使用,
            System.out.println(i.getClass());//class [I  I是int类型
            System.out.println(i.getClass().getSuperclass());//class java.lang.Object
            
            char[] c = new char[1];//,不是主动使用,
            System.out.println(c.getClass());//class [C  C是char类型
            System.out.println(c.getClass().getSuperclass());//class java.lang.Object
            
            boolean[] b = new boolean[1];//,不是主动使用,
            System.out.println(b.getClass());//class [Z  Z是boolean类型
            System.out.println(b.getClass().getSuperclass());//class java.lang.Object
            
            short[] s = new short[1];//,不是主动使用,
            System.out.println(s.getClass());//class [S  S是short类型
            System.out.println(s.getClass().getSuperclass());//class java.lang.Object
            
            long[] l = new long[1];//,不是主动使用,
            System.out.println(l.getClass());//class [J  J是long类型
            System.out.println(l.getClass().getSuperclass());//class java.lang.Object
            
            byte[] by = new byte[1];//,不是主动使用,
            System.out.println(by.getClass());//class [B  B是byte类型
            System.out.println(by.getClass().getSuperclass());//class java.lang.Object
        }
    }
    //一个接口初始化,并不要求父接口也初始化。
    //真正使用父接口时候(如使用接口中的常量时候)才不会初始化。类的初始化是会初始化父类的。
    
    //final常量是会放到调用类的常量池中去的,不会引起定义常量的类的初始化,运行期间就放进去了。
    //如果常量是随机数运行期间才能确定的,那么就会引起定义常量的类的初始化。
    public class sd {
        public static void main(String[] args) {
            System.out.println(Ic.b);
        }
    }
    
    interface Ip {
        public static int a = 5;
    }
    
    interface Ic extends Ip {
        public static int b = 6;
    }
    package com.ssss;
    public class sd {
        @SuppressWarnings("static-access")
        public static void main(String[] args) {
            Singleton ss = Singleton.get();//先去初始化Singleton类,最后调用get方法。
            System.out.println(ss.i);//1
            System.out.println(ss.j);//0
        }
    }
    @SuppressWarnings("static-access")
    class Singleton {
        public static int i;
        /*static {
            System.out.println("s "+s );//s报错,找不到定义。
        }*/
        public static Singleton s = new Singleton();//看到new就会去执行构造函数。在执行下面的静态块。否则不执行构造函数。
        static {
            System.out.println("s.i2:"+s.i);//1
            System.out.println("s.j2:"+s.j);//1
        }
        private Singleton() {
            System.out.println("i0:"+i);//i:0
            System.out.println("j0:"+j);//j:0,
            i++;
            j++;
            System.out.println("i:"+i);//i:1
            System.out.println("j:"+j);//j:1,j这里是1,但是后面把j赋值为了0,所以get时候是0.
            System.out.println("s.i:"+s.i);//1
            System.out.println("s.j:"+s.j);//1
        }
    //    public static int j = 0;//就是执行这里,再去执行get方法,把对象的属性j赋值成了0
        
        public static Singleton get() {
            System.out.println("i1:"+i);//i1:1
            System.out.println("j1:"+j);//j1:0
            System.out.println("s.i1:"+s.i);//1
            System.out.println("s.j1:"+s.j);//0
            return s;
        }
        static {
            System.out.println("s.i3:"+s.i);//1
            System.out.println("s.j3:"+s.j);//1
        }
        public static int j = 0;//就是执行这里,再去执行get方法,把对象的属性j赋值成了0。即使这行代码放在这里,j也会是0
        //因为先初始化Singleton类,get方法最后调用。即使get方法是静态的,也是在main函数中调用的时候再去执行,不会初始化执行,初始化只会执行静态代码块。构造函数也只是有new才会执行。初始化从上到下执行。
        static {
            System.out.println("s.i4:"+s.i);//1
            System.out.println("s.j4:"+s.j);//0
        }
    }
    /*i0:0
    j0:0
    i:1
    j:1
    s.i:1
    s.j:1
    s.i2:1
    s.j2:1
    s.i3:1
    s.j3:1
    s.i4:1
    s.j4:0
    i1:1
    j1:0
    s.i1:1
    s.j1:0
    1
    0*/
    package com.ssss;
    public class sd {
        @SuppressWarnings("static-access")
        public static void main(String[] args) {
            Singleton ss = Singleton.get();//先去初始化Singleton类,最后调用get方法。
            System.out.println(ss.i);//1
            System.out.println(ss.j);//0
        }
    }
    @SuppressWarnings("static-access")
    class Singleton {
        public static int i;
        public static Singleton s = new Singleton();//看到new就会去执行构造函数。在执行下面的静态块。否则不执行构造函数。
        public static int j = 0; 
        static {//不加static,则是最先执行,然后执行构造函数,且每个对象都会执行一遍
            System.out.println("s.i2:"+s.i);//1
            System.out.println("s.j2:"+s.j);//0
        }
        private Singleton() {
            System.out.println("i0:"+i);//i:0
            System.out.println("j0:"+j);//j:0,
            i++;
            j++;
            System.out.println("i:"+i);//i:1
            System.out.println("j:"+j);//j:1,         System.out.println("s.i:"+s.i);//1
            System.out.println("s.j:"+s.j);//1
        }
        
        public static Singleton get() {
            System.out.println("i1:"+i);//i1:1
            System.out.println("j1:"+j);//j1:0
            System.out.println("s.i1:"+s.i);//1
            System.out.println("s.j1:"+s.j);//0
            return s;
        }
        static {
            System.out.println("s.i3:"+s.i);//1
            System.out.println("s.j3:"+s.j);//0
        }
    }
    /*i0:0
    j0:0
    i:1
    j:1
    s.i:1
    s.j:1
    s.i2:1
    s.j2:0
    s.i3:1
    s.j3:0
    i1:1
    j1:0
    s.i1:1
    s.j1:0
    1
    0*/
    package com.ssss;
    public class sd {
        @SuppressWarnings("static-access")
        public static void main(String[] args) {
            Singleton ss = Singleton.get();//先去初始化Singleton类,最后调用get方法。
            System.out.println(ss.i);//1
            System.out.println(ss.j);//1
        }
    }
    @SuppressWarnings("static-access")
    class Singleton {
        public static int i;
        public static int j = 0; 
        public static Singleton s = new Singleton();//看到new就会去执行构造函数。在执行下面的静态块。否则不执行构造函数。
        static {
            System.out.println("s.i2:"+s.i);//1
            System.out.println("s.j2:"+s.j);//1
        }
        private Singleton() {
            System.out.println("i0:"+i);//i:0
            System.out.println("j0:"+j);//j:0 
            i++;
            j++;
            System.out.println("i:"+i);//i:1
    System.out.println("j:"+j);//j:1         System.out.println("s.i:"+s.i);//1
            System.out.println("s.j:"+s.j);//1
        }
        
        public static Singleton get() {
            System.out.println("i1:"+i);//i1:1
            System.out.println("j1:"+j);//j1:1
            System.out.println("s.i1:"+s.i);//1
            System.out.println("s.j1:"+s.j);//1
            return s;
        }
        static {
            System.out.println("s.i3:"+s.i);//1
            System.out.println("s.j3:"+s.j);//1
        }
    }
    /*i0:0
    j0:0
    i:1
    j:1
    s.i:1
    s.j:1
    s.i2:1
    s.j2:1
    s.i3:1
    s.j3:1
    i1:1
    j1:1
    s.i1:1
    s.j1:1
    1
    1
    */

    类加载器:

    1. 虚拟机自带类加载器

    1.1根类加载器(Bootstrap

    1.2扩展类加载器(Extension

    1.3系统(应用)类加载器(System,App

    1. ClassLoader的子类

    Loader1发起加载Sample类,但是根加载器和扩展加载器都是加载特定目录的类,因此最终是由系统加载器加载成功,并把结果返回给loader1加载器。首先是向上委托到根,加载不了又向下委托,一个双向循环

     

    rt.jar是使用最多的类,平时使用的都是这个里面的。

    定义类加载器:加载这个类成功的类加载器。Sample类是由系统类加载器加载成功的,系统类加载器就是定义类加载器。

     

    package com.ssss;
    public class TT {
        public static void main(String[] args) throws Exception {
            Class cl = Class.forName("java.lang.String");
            System.out.println(cl.getClassLoader());//null。返回类加载器,如果是null就是bootStrap类加载器加载的。
            
            Class cl1 = Class.forName("com.ssss.C");//反射,主动使用,static会执行
            System.out.println(cl1.getClassLoader());//sun.misc.Launcher$AppClassLoader@73d16e93,,内部类,系统加载器/应用加载器。
            //应用加载器 加载的是  工程环境变量 classpath里面的类。
            
            System.out.println("-------------------------------");
            ClassLoader l = ClassLoader.getSystemClassLoader();//系统加载器
            Class dd = l.loadClass("com.ssss.C");//只是loadClass,不是对类的主动使用,不是初始化,不执行static代码块
            System.out.println(dd);//class com.ssss.C
    
                                                                                                  System.out.println("==============================");
             ClassLoader l1 = l.getParent();
        System.out.println(l1);//sun.misc.Launcher$ExtClassLoader@15db9742
            ClassLoader l2 = l1.getParent();
            System.out.println(l2);//null
    
        }
    }
    class C {
        static {
            System.out.println("ccccc");
        }
    }

     

    public class TT {
        public static void main(String[] args) throws Exception {
            ClassLoader t = Thread.currentThread().getContextClassLoader();
            System.out.println(t);//sun.misc.Launcher$AppClassLoader@73d16e93。加载应用的加载器。
            
            String s = "com\ssss\C.class";
            Enumeration<URL> urls = t.getResources(s);
            while(urls.hasMoreElements()) {
                URL u = urls.nextElement();
                System.out.println(u);//"com\ssss\C.class"
            }
            
            System.out.println("----=======-------========-----=======");
            Class c = TT.class;
            System.out.println(c.getClassLoader());//sun.misc.Launcher$AppClassLoader@73d16e93
            
            Class c1 = String.class;
            System.out.println(c1.getClassLoader());//null。根加载器。String在rt.jar中
        }
    }

    类加载器加载的是类,不是对象线程上下文clssloaderAppClassLoader

     

     

     

     

  • 相关阅读:
    [ARC117F]Gateau
    [ARC117D]Miracle Tree
    [loj3504]支配
    [gym102511K]Traffic Blights
    [loj3501]图函数
    [loj3503]滚榜
    [loj3500]矩阵游戏
    [loj2135]幻想乡战略游戏
    [cf720D]Slalom
    [cf1349E]Slime and Hats
  • 原文地址:https://www.cnblogs.com/yaowen/p/10938566.html
Copyright © 2011-2022 走看看