【问题标题】:Why can't object size be measured in a managed environment?为什么不能在托管环境中测量对象大小?
【发布时间】:2015-08-13 14:58:43
【问题描述】:

因此,stackoverflow 上存在许多问题的变体,询问如何测量对象的大小(例如 this one)。答案指向了一个事实,没有太多详细说明,这是不可能的。有人可以详细解释为什么不可能或为什么测量物体大小没有意义吗?

【问题讨论】:

  • 您能举个例子吗?为什么要测量对象的大小?
  • 我想说这个问题的答案相当详细。你到底有什么不明白的?许多托管语言中的对象都有额外的开销,其中包括用于锁定/gc/等的结构。它们还可能具有填充以允许对齐的成员访问,以及填充的内容和数量可能因架构而异。
  • @DarkFalcon 所以同一个类的两个对象会有相同的开销?还是这些是随机的?有没有办法找出存在多少这样的开销,甚至可以单独找出它们的大小?
  • @mastah 说找出哪个类平均比其他类占用更多内存

标签: java c# memory


【解决方案1】:

我从您询问的关于 Java 和 C# 中对象大小测量的标签中猜测。对 C# 了解不多,因此以下仅适用于 Java。

此外,单个对象的浅层尺寸和滞留尺寸之间存在差异,我想您是在询问浅层尺寸(这是推导滞留尺寸的基础)。

我也将您的术语托管环境解释为您只想知道在特定 JVM 中运行时对象的大小(例如,仅计算大小源代码)。

我的简短回答首先:

  • 测量对象大小是否有意义?是的,它确实。任何在内存限制下运行的应用程序的开发人员都乐于了解类布局和对象分配对内存的影响。
  • 是否不可能在托管环境中进行测量?不它不是。 JVM 必须知道其对象的大小,因此必须能够报告对象的大小。如果我们有办法要求的话。

长答案:

无法仅从类定义中导出对象大小的原因有很多,例如:

  • Java 语言规范仅给出原始类型的下限内存要求。 int 至少占用 4 个字节,但实际大小取决于 VM。

  • 不确定语言规范中关于引用大小的说明。对 JVM 中可能的对象数量是否有任何限制(这会对对象引用的内部存储大小产生影响)?今天的 JVM 使用 4 个字节作为引用指针。

  • JVM 可能(并且确实)填充对象字节以在可能扩展对象大小的某个边界处对齐。现在的 JVM 通常将对象内存对齐在 8 字节边界。

但所有这些原因不适用于使用实际内存布局的 JVM 运行时,最终允许其分代垃圾收集器推送对象,因此必须能够报告对象大小。

那么我们如何知道运行时的对象大小呢? 在 Java 1.5 中,我们得到了java.lang.instrument.Instrumentation#getObjectSize(Object)。 Javadoc 说:

返回特定于实现的近似值 指定对象消耗的存储空间。结果可能包括一些 或所有对象的开销,因此可用于比较 在一个实现中,但不在实现之间。估计 在 JVM 的单次调用期间可能会发生变化。

带着一粒盐阅读这告诉我,有一种合理的方法可以在运行时的某个时间点获得对象的确切浅尺寸。

【讨论】:

  • 现在说得通了!感谢您的帮助!
【解决方案2】:
  • 获取对象的大小很容易。

  • 如果对象很大并且我们使用 IO 流来获取大小,则获取对象大小的开销可能很小。

  • 如果您必须非常频繁地获取较大对象的大小,则必须小心。

看看下面的代码。

 import java.io.*;  

    class ObjectData implements Serializable{
        private int id=1;;
        private String name="sunrise76";
        private String city = "Newyork";
        private int dimensitons[] = {20,45,789}; 
    }

    public class ObjectSize{
        public static void main(String args[]){
            try{
            ObjectData data = new ObjectData();
            ByteArrayOutputStream b = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(b);
            oos.writeObject(data);
            System.out.println("Size:"+b.toByteArray().length);
            }catch(Exception err){
                err.printStackTrace();
            }
        }
    }

【讨论】:

  • 对象的序列化字节不是JVM中对象内存的快照,因此不允许计算其内存大小。例如,对象的序列化版本将包含其类名(作为序列化字符串),而 JVM 对象仅具有指向其类对象的指针。还是喜欢你的做法。
  • instrumentation api 的唯一问题:它不包括作为该对象一部分的其他对象的大小。它不是对象的深度大小。
  • @sunrise76 感谢您的帮助!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
  • 1970-01-01
  • 2020-02-13
相关资源
最近更新 更多