• JVM总结1:jvm结构图 类加载器 方法区 栈


    jvm是什么:

    java virtual machine,程序在编译时,通过jvm编译为字节码(class文件),这样可以跨平台执行,在执行时是由jvm解释执行的。

    jvm体系图:

     

     

    类加载器:

    运行时,.class文件由类加载器加载到内存中成为Class类的一个实例,每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。

    有三种类加载器,他们之间有继承关系,加载的类的范围也不一样。

    这是继承关系:

     

     以下代码可以用来测试一下类加载器

    public class TestClass {
        public static void main(String[] args) {
            Car car = new Car();
            System.out.println(car.getClass());
            System.out.println(car.getClass().getClassLoader());
            System.out.println(car.getClass().getClassLoader().getParent());
            String a="dfsf";
            System.out.println(a.getClass().getClassLoader());
        }
    }

    双亲委派机制:

    • 如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成。
    • 每一个层次的类加载器都是如此。因此,所有的加载请求最终都应该传送到顶层的启动类加载器中。
    • 只有当父加载器反馈自己无法完成这个加载请求时(搜索范围中没有找到所需的类),子加载器才会尝试自己去加载。
    • 为了保护安全,不能用户自己随便写一个String类,结果就加载了这个类。

    Native方法

    在类中突然看到这样的代码,像接口或者抽象类里面的,没有实现。
    带了native关键词,代表java作用范围达不到了,回去调用c语言库。

    这种start0方法就进了本地方法栈---本地方法接口--本地方法库

    JNI java native interface

    native还是用的少的--底层,硬件,掌握概念即可,企业开发中少见
     

    PC寄存器

     方法区

    《深入理解Java虚拟机》书中对方法区(Method Area)存储内容描述如下:它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。
    在 JDK7 及以前,习惯上把方法区,称为永久代。JDK8开始,使用元空间取代了永久代。JDK 1.8后,元空间与永久代最大的区别在于: 元空间不在虚拟机设置的内存中,而是使用本地内存
    static,final,方法,常量池
    那么不带static的方法放在哪个区域呢
    通过实例引用调用实例方法的时候,先从方法区中对象的实际类型信息找,找不到的话再去父类类型信息中找。

    对象的加载过程

    public class Person{
        int age;
        String name;
        public void walk() {
            System.out.println("我正在走路。。。。");
        }
    }
    然后我们测试一下:
    public class Test {
        public static void main(String[] args) {
            Person person = new Person();
            person.name = "java的架构师技术栈";
            person.age = 18;
            person.walk();
        }
    }
    我们分析一下这个过程

    第一步,JVM去方法区寻找Test类的代码信息,如果有直接调用,没有的话使用类的加载机制把类加载进来。同时把静态变量、静态方法、常量加载进来。这里加载的是(“冯冬冬的IT技术栈”,“冯XX”);这是因为字符串是常量,age中的18是基本类型。

    第二步,jvm进入main方法,看到Person person=new Person()。首先分析Person这个类,同样的寻找Person类的代码信息,有就加载,没有的话类加载机制加载进来。同时也加载静态变量、静态方法、常量(“我正在走路。。。”)

    第三步,jvm接下来看到了person,person在main方法内部,因而是局部变量,存放在栈空间中。

    第四步,jvm接下来看到了new Person()。new出的对象(实例),存放在堆空间中。

    第五步,jvm接下来看到了“=”,把new Person的地址告诉person变量,person通过四字节的地址(十六进制),引用该实例。 是不是有点晕,别着急,画个图看一下。

    第六步,jvm看到person.name = “冯冬冬的IT技术栈”;person通过引用new Person实例的name属性,该name属性通过地址指向常量池的"冯冬冬的IT技术栈"。

    第七步,jvm看到person.age = 18; person的age属性是基本数据类型,直接赋值。

    第八步,jvm看到person.walk(); 调用实例的方法时,并不会在实例对象中生成一个新的方法,而是通过地址指向方法区中类信息的方法。走到这一步再看看图怎么变化的

    虚拟机栈

    栈和队列原来老是有点弄得晕,现在看这个比喻挺好的。

    栈就是,先放进去当然后面才能拿出来。

    队列就是先进先出了FIFO(first in first out)。

    栈是跟线程的,生命周期和线程同步。每个线程对应一个独立的stack。线程结束,栈内存就释放,对于栈不存在垃圾回收问题。

     这个栈的过程,栈走完之后会弹出栈。

    栈是由这些栈帧组成的,一个方法对应一个栈帧。

     方法中的基本类型变量是放在这个本地变量表中的,非基本类型会在这放一个引用(指向内存地址)。

    JVM堆中存的是对象。JVM栈中存的是基本数据类型和JVM堆中对象的引用。一个对象的大小是不可估计的,或者说是可以动态变化的,但是在JVM栈中,一个对象只对应了一个4btye的引用(JVM堆JVM栈分离的好处:))。

    为什么不把基本类型放JVM堆中呢?因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型,所以不会出现动态增长的情况—— 长度固定,因此JVM栈中存储就够了,如果把他存在JVM堆中是没有什么意义的(还会浪费空间,后面说明)。可以这么说,基本类型和对象的引用都是存放在 JVM栈中,而且都是几个字节的一个数,因此在程序运行时,他们的处理方式是统一的。但是基本类型、对象引用和对象本身就有所区别了,因为一个是JVM栈 中的数据一个是JVM堆中的数据。最常见的一个问题就是,Java中参数传递时的问题。

    StackOverflow,栈溢出错误。如果你无限压栈就会,例如递归调用方法层数太多。

  • 相关阅读:
    自学Python三个月能赚钱吗?
    Python如何优雅删除字符列表空字符及None元素
    Python如何对XML 解析
    Python爬虫爬取博客实现可视化过程解析
    更改折旧范围
    尚未被定义为调节科目
    查看事务码
    固定资产创建屏幕分类,必填,字段组规则,折旧科目的设置等
    固定资产配置非税购置的进项税标识符、指定折旧表,分配公司代码
    维护消息
  • 原文地址:https://www.cnblogs.com/take-it-easy/p/13881455.html
Copyright © 2020-2023  润新知