是什么导致内存中单个对象的大小?
我知道原语和引用会,但是还有其他吗?方法的数量及其长度是否重要?
这完全取决于实现,但是有一些因素会影响Java中的对象大小。
首先,Java对象中字段的数量和类型肯定会影响空间使用,因为您至少需要拥有容纳该对象所有字段所需的存储空间。但是,由于填充,对齐和指针压缩的优化,没有直接公式可用于精确计算以这种方式使用了多少空间。
对于方法,通常来说,对象中方法的数量对其大小没有影响。方法通常使用称为虚拟功能表(或“
vtables”)的功能来实现,该功能可以在恒定时间内通过基类引用来调用方法。通常,通过在多个对象之间共享vtable的单个实例,然后让每个对象存储指向vtable的单个指针,来存储这些表。
接口方法使此图有点复杂,因为有几种不同的实现方式。一种实现为每个接口添加了一个新的vtable指针,因此实现的接口数量可能会影响对象大小,而其他的则不会。同样,它取决于实现方式,如何将它们实际存储在内存中,因此您无法确定这是否会带来内存成本。
据我所知,当今还没有实现方法长度影响对象大小的JVM实现。通常,每种方法的一个副本仅存储在内存中,然后在特定对象的所有实例之间共享代码。使用更长的方法可能需要更多的
总
内存,但不会影响类html" target="_blank">实例的每个对象的内存。就是说,JVM规范不保证一定是这种情况,但是我无法想到一个合理的实现,该实现会为方法代码每个对象花费额外的空间。
除了字段和方法外,许多其他因素也会影响对象的大小。这里是一些:
根据JVM使用的垃圾收集器类型,每个对象可能都有额外的存储空间来保存有关该对象是否处于活动状态,已死亡,可到达等信息。这可能会增加存储空间,但是用完了您的控制权。在某些情况下,JVM可能会通过尝试将对象存储在堆栈而不是堆上来优化对象大小。在这种情况下,某些类型的对象甚至可能没有开销。
如果使用同步,则可能为对象分配了额外的空间,以便可以对其进行同步。JVM的某些实现直到需要时才为对象创建监视器,因此,如果不使用同步,则最终可能会拥有较小的对象,但不能保证会如此。
另外,为了支持像instanceof
和类型转换这样的运算符,每个对象都可以保留一些空间来保存类型信息。通常,它与对象的vtable捆绑在一起,但是不能保证这是正确的。
如果使用断言,则某些JVM实现将在您的类中创建一个字段,其中包含是否启用断言。然后用于在运行时禁用或启用断言。同样,这是特定于实现的,但是请记住一点。
如果您的类是非静态内部类,则可能需要保留对包含它的类的引用,以便它可以访问其字段。但是,如果您从未使用过,JVM可能会优化它。
如果使用匿名内部类,则该类可能需要保留额外的空间来容纳final
在其封闭范围内可见的变量,以便可以在类内部对其进行引用。此信息是复制到类字段中还是仅本地存储在堆栈中,这是特定于实现的,但它可能会增加对象的大小。
如果它无法通过其他任何方式计算哈希值,则某些实现Object.hashCode()
或System.identityHashCode(Object)
可能需要将额外的信息存储在包含该哈希码值的每个对象中(例如,如果对象可以在内存中重定位)。这可能会增加每个对象的大小。
问题内容: 查理·亨特(Charlie Hunt)在他的演讲中说,大型对象对JVM GC不利。因为: 大对象的分配和初始化非常昂贵。 不同大小的大对象可能会导致Java堆碎片化。 如何定义大对象?我怎么知道物体是否是大物体?谢谢 问题答案: 该定义取决于平台,JVM和JVM配置。例如,以下摘自Michael Kopp 的三篇大型JVM 博客文章 中的“垃圾回收如何不同” : 大小物体 JRocki
问题内容: 我有一个应用程序,它读取带有大量数据行的CSV文件。我根据数据类型为用户提供了行数的摘要,但我想确保不会读取太多的数据行并导致OutOfMemoryErrors。每行转换为一个对象。有没有一种简便的方法以编程方式找出该对象的大小?是否有一个引用定义了一个原始类型和对象引用有多大VM? 现在,我的代码可以读取多达32,000行,但我还想让代码显示尽可能多地读取行,直到使用32 MB内存为
问题内容: 每当我学习垃圾收集器时,都会听到术语“对象图”。到底是什么意思? 问题答案: 对象具有对其他对象的引用,这些对象又可以具有对更多对象(包括起始对象)的引用。这将创建对象图,在可及性分析中很有用。例如,如果起始对象是可到达的(例如,它在线程的本地堆栈中),则图形中的所有对象都是可到达的,并且确切的垃圾收集器无法收集任何这些对象。同样,如果我们创建所有可到达对象的列表,则从一组活动对象(根
问题内容: 你能给我一些有关对象头中确切存储的信息吗?我知道,这可能取决于JVM,但也许至少对于HotSpot?我正在寻找专门针对第一行的确切描述。 我已经阅读了一些信息,这些信息无法用我找到的信息进行正面验证。也许你有指向全部内容的OpenJDK Wiki的链接? 问题答案: 对象头由一个标记词和一个klass指针组成。 所述标记字具有(字大小在32位体系结构中,在64位体系结构)和 在克拉斯指
问题内容: 这是 不是 增加Java的堆的最大尺寸的虚拟机启动后。技术原因是什么?垃圾回收算法是否取决于要使用固定数量的内存?还是出于安全原因,通过消耗所有可用内存来防止Java应用程序从DOS的系统中移至其他应用程序? 问题答案: 最后我知道在Sun的JVM中,必须在连续的地址空间中分配整个堆。我想对于大堆值,很难在启动后将其添加到您的地址空间中,同时又要确保它保持连续。您可能需要在启动时获取它