这完全取决于实现,但是有一些因素会影响Java中的对象大小。
首先,Java对象中字段的数量和类型肯定会影响空间使用,因为您至少需要拥有容纳该对象所有字段所需的存储空间。但是,由于填充,对齐和指针压缩的优化,没有直接公式可用于精确计算以这种方式使用了多少空间。
对于方法,通常来说,对象中方法的数量对其大小没有影响。方法通常使用称为虚拟功能表(或“
vtables”)的功能来实现,该功能可以在恒定时间内通过基类引用来调用方法。通常,通过在多个对象之间共享vtable的单个实例,然后让每个对象存储指向vtable的单个指针,来存储这些表。
接口方法使此图有点复杂,因为有几种不同的实现方式。一种实现为每个接口添加了一个新的vtable指针,因此实现的接口数量可能会影响对象大小,而其他的则不会。同样,它取决于实现方式,如何将它们实际存储在内存中,因此您无法确定这是否会带来内存成本。
据我所知,当今还没有实现方法长度影响对象大小的JVM实现。通常,每种方法的一个副本仅存储在内存中,然后在特定对象的所有实例之间共享代码。使用更长的方法可能需要更多的
总
内存,但不会影响类实例的每个对象的内存。就是说,JVM规范不保证一定是这种情况,但是我无法想到一个合理的实现,该实现会为方法代码每个对象花费额外的空间。
除了字段和方法外,许多其他因素也会影响对象的大小。这里是一些:
根据JVM使用的垃圾收集器类型,每个对象可能都有额外的存储空间来保存有关该对象是否处于活动状态,已死亡,可到达等信息。这可能会增加存储空间,但是用完了您的控制权。在某些情况下,JVM可能会通过尝试将对象存储在堆栈而不是堆上来优化对象大小。在这种情况下,某些类型的对象甚至可能没有开销。
如果使用同步,则可能为对象分配了额外的空间,以便可以对其进行同步。JVM的某些实现直到需要时才为对象创建监视器,因此,如果不使用同步,则最终可能会拥有较小的对象,但不能保证会如此。
另外,为了支持像
instanceof和类型转换这样的运算符,每个对象都可以保留一些空间来保存类型信息。通常,它与对象的vtable捆绑在一起,但是不能保证这是正确的。
如果使用断言,则某些JVM实现将在您的类中创建一个字段,其中包含是否启用断言。然后用于在运行时禁用或启用断言。同样,这是特定于实现的,但是请记住一点。
如果您的类是非静态内部类,则可能需要保留对包含它的类的引用,以便它可以访问其字段。但是,如果您从未使用过,JVM可能会优化它。
如果使用匿名内部类,则该类可能需要保留额外的空间来容纳
final在其封闭范围内可见的变量,以便可以在类内部对其进行引用。此信息是复制到类字段中还是仅本地存储在堆栈中,这是特定于实现的,但它可能会增加对象的大小。
如果它无法通过其他任何方式计算哈希值,则某些实现
Object.hashCode()或
System.identityHashCode(Object)可能需要将额外的信息存储在包含该哈希码值的每个对象中(例如,如果对象可以在内存中重定位)。这可能会增加每个对象的大小。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)