0xb*_*7ed 52 java oop inheritance jvm internal-representation
在互联网上有各种各样的文章,试图通过经验估计java.lang.Object特定JVM实现的开销.例如,我在一些JVM中看到了一个Object 估计为8字节的裸大小开销.
我想知道的是,extends关系的典型JVM实现是否在类层次结构的每个级别引入增量大小开销.换句话说,假设您有一个具有N级子类的类层次结构.是类实例O(1)还是O(N)的内存中表示的开销?
我想它是O(1)因为虽然你需要成为Java Object(vtable,类链)的一些隐藏的蓬松东西的大小会随着继承层次结构的增长而增长,但它们每个类增长,而不是每个实例,JVM实现可以在连接到每个实体的常量大小的头中存储这些实体的常量大小的指针Object.
所以从理论上讲,直接附加到任何Java对象的内存中表示的开销应该是O(1)的继承深度N.有谁知道它在实践中是否正确?
Sot*_*lis 23
Java虚拟机不要求对象的任何特定内部结构.
因此规范并不关心你是如何做到的.但 ......
在Oracle的一些Java虚拟机实现中,对类实例的引用是指向句柄的指针,该句柄本身是一对指针:一个指向包含对象方法的表和指向表示Class对象的指针对象的类型,另一个是从堆为对象数据分配的内存.
因此,在典型的Oracle实现中,方法是O(1).此方法表是每个类的方法区域.
Java虚拟机具有在所有Java虚拟机线程之间共享的方法区域.方法区域类似于传统语言的编译代码的存储区域或类似于操作系统进程中的"文本"段.它存储每类结构,例如运行时常量池,字段和方法数据,以及方法和构造函数的代码,包括类和实例初始化以及接口初始化中使用的特殊方法(第2.9节).
另外,关于方法条目
的
method_info结构表示由这个类或接口类型声明的所有方法,包括实例方法,类方法,例如初始化方法(§2.9),以及任何类或接口初始化方法(§2.9).methods表不包括表示从超类或超接口继承的方法的项.
tuc*_*uxi 23
如有疑问,请查看源(当然,一个源;每个JVM可以自由选择如何做到这一点,因为标准不强制要求任何内部表示).所以我看一下,在JDK 7-u60的热点JVM的实现中发现了以下注释:
// A Klass is the part of the klassOop that provides:
// 1: language level class object (method dictionary etc.)
// 2: provide vm dispatch behavior for the object
// Both functions are combined into one C++ class. The toplevel class "Klass"
// implements purpose 1 whereas all subclasses provide extra virtual functions
// for purpose 2.
// One reason for the oop/klass dichotomy in the implementation is
// that we don't want a C++ vtbl pointer in every object. Thus,
// normal oops don't have any virtual functions. Instead, they
// forward all "virtual" functions to their klass, which does have
// a vtbl and does the C++ dispatch depending on the object's
Run Code Online (Sandbox Code Playgroud)
我读它的方式,这意味着,对于这个(非常流行的)实现,对象实例只存储指向其类的指针.具有更长或更短的继承链的类的每个实例的成本实际上为0.这些类本身确实占用了内存空间(但每个类只有一次).深度继承链的运行时效率是另一回事.