• 先有Class还是先有Object?


    先有Class还是先有Object?

    Java的对象模型中:

    1. 所有的类都是Class类的实例,Object是类,那么Object也是Class类的一个实例。
    2. 所有的类都最终继承自Object类,Class是类,那么Class也继承自Object。

    这就像是先有鸡还是先有蛋的问题,请问实际中JVM是怎么处理的?
    此外,可能的话,介绍一下其它面向对象语言是怎么处理这个问题的。

     

     

    RednaxelaFX从事JVM研发

    简短答案:“鸡・蛋”问题通常都是通过一种叫“自举”(bootstrap)的过程来解决的。

    首要要引用题主的问题并指出它的问题:
    Java的对象模型中:
    1. 所有的类都是Class类的实例,Object是类,那么Object也是Class类的一个实例。
    2. 所有的类都最终继承自Object类,Class是类,那么Class也继承自Object。
    这个问题中,第1个假设是错的:java.lang.Object是一个Java类,但并不是java.lang.Class的一个实例。后者只是一个用于描述Java类与接口的、用于支持反射操作的类型。这点上Java跟其它一些更纯粹的面向对象语言(例如Python和Ruby)不同。
    而第2个假设是对的:java.lang.Class是java.lang.Object的派生类,前者继承自后者。

    虽然第1个假设不对,但“鸡蛋问题”仍然存在:在一个已经启动完毕、可以使用的Java对象系统里,必须要有一个java.lang.Class实例对应java.lang.Object这个类;而java.lang.Class是java.lang.Object的派生类,按“一般思维”前者应该要在后者完成初始化之后才可以初始化…

    事实是:这些相互依赖的核心类型完全可以在“混沌”中一口气都初始化好,然后对象系统的状态才叫做完成了“bootstrap”,后面就可以按照Java对象系统的一般规则去运行。JVM、JavaScript、Python、Ruby等的运行时都有这样的bootstrap过程。

    其实“鸡蛋问题”的根本矛盾就在于假定了“鸡”或“蛋”的其中一个要先进入“完全可用”的状态。而许多现实中被简化为“鸡蛋问题”的情况实际可以在“混沌”中把“鸡”和“蛋”都初始化好,而不存在先后问题;在它们初始化的过程中,两者都不处于“完全可用”状态。

    在“混沌”(boostrap过程)里,JVM可以为对象系统中最重要的一些核心类型先分配好内存空间,让它们进入[已分配空间]但[尚未完全初始化]状态。此时这些对象虽然已经分配了空间,但因为状态还不完整所以尚不可使用。
    然后,通过这些分配好的空间把这些核心类型之间的引用关系串好。到此为止所有动作都由JVM完成,尚未执行任何Java字节码。
    然后这些核心类型就进入了[完全初始化]状态,对象系统就可以开始自我运行下去,也就是可以开始执行Java字节码来进一步完成Java系统的初始化了。

    在HotSpot VM里,有一个叫做“Universe”的C++类用于记录对象系统的总体状态。它有这么两个有趣的字段记录当前是处于bootstrapping阶段还是已经完全初始化好:
    jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/memory/universe.hpp
      static bool is_bootstrapping()                      { return _bootstrapping; }
      static bool is_fully_initialized()                  { return _fully_initialized; }
    
    然后Universe::genesis()函数会在bootstrap阶段中创建核心类型的对象模型:
    jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/memory/universe.cpp
    (“genesis”是创世纪的意思,多么形象)
    其中会调用SystemDictionary::initialize()来初始化对象系统的核心类型:
    jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/classfile/systemDictionary.cpp
    其中会进一步跑到SystemDictionary::initialize_preloaded_classes()来创建java.lang.Object、java.lang.Class等核心类型:
    jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/classfile/systemDictionary.cpp
    这个函数在加载了java.lang.Object、java.lang.Class等核心类型后会调用Universe::fixup_mirrors()来完成前面说的“把引用关系串起来”的动作:
      // Fixup mirrors for classes loaded before java.lang.Class.
      // These calls iterate over the objects currently in the perm gen
      // so calling them at this point is matters (not before when there
      // are fewer objects and not later after there are more objects
      // in the perm gen.
      Universe::initialize_basic_type_mirrors(CHECK);
      Universe::fixup_mirrors(CHECK);
    
    jdk8u/jdk8u/hotspot: ade5be2b1758 src/share/vm/memory/universe.cpp
    void Universe::fixup_mirrors(TRAPS) {
      // Bootstrap problem: all classes gets a mirror (java.lang.Class instance) assigned eagerly,
      // but we cannot do that for classes created before java.lang.Class is loaded. Here we simply
      // walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note
      // that the number of objects allocated at this point is very small.
    
      // ...
    }
    
    就是这样。
  • 相关阅读:
    玩游戏 学Flex布局
    解决:父级元素不能被子元素内容撑开的解决办法,父级元素没有高度的解决办法
    Flex 项目属性:flex 布局示例
    display: flex; 布局
    box-sizing 的作用
    <a>标签里面直接嵌套图片,<img>下面出现一小段空白的原因
    ucore操作系统实验学习笔记2
    ucore 操作系统学习笔记1 -- 环境搭建
    LeetCode题解之 Assign Cookies
    LeetCode题解之Lemonade Change
  • 原文地址:https://www.cnblogs.com/01picker/p/4498499.html
Copyright © 2020-2023  润新知