8

Java 虚拟机也可以int对字段使用 -sized 宽度short(这取决于它们的内部实现)。只有数组 ( short[]) 是例外,始终保证它们占用的空间int[]也比内部少)。达尔维克呢?

例如,我有一个包含 50 个类型字段的类short。有时在我的应用程序中,存在 10000 个此类。这意味着short字段应该使用 1MB 的内存,但是如果Dalvik 在short内部使用 4 个字节的值,那么这将是 2MB 的内存使用。

我应该期望 Dalvik 使用多少内存?(这是指它的内部内存使用,我知道它可能不会反映在系统内存使用中,例如因为 Dalvik 已经从系统中保留了更多的内存。)

4

2 回答 2

4

在 dalvik 中,double 和 long 字段是 8 个字节,其他所有内容(包括 short)都是 4 个字节。

另一方面,短数组每个元素占用 2 个字节(除了数组+对象簿记的前期空间)。

数组

new-array操作码调用(第dvmAllocArrayByClass71 行)分配空间。然后调用dvmAllocPrimitiveArray(第 113 行)。在 switch in 中dvmAllocPrimitiveArray,“S”大小写用于短数组。你可以看到它调用allocArray(第 38 行)width=2。

在 内allocArray,它执行以下计算来计算数组的大小:

size_t elementShift = sizeof(size_t) * CHAR_BIT - 1 - CLZ(elemWidth);
size_t elementSize = length << elementShift;
size_t headerSize = OFFSETOF_MEMBER(ArrayObject, contents);
size_t totalSize = elementSize + headerSize;

简而言之,在 32 位系统上,此计算为:

size_t elementShift = (4 * 8) - 1 - 30; //== 1;
size_t elementSize = length << 1; //i.e. length * 2
size_t headerSize = <some constant value>;
size_t totalSize = length*2 + <some constant value>;

短数组每个元素占用 2 个字节。

字段

new-instance操作码调用(第dvmAllocObject181 行)为新对象分配空间。分配的大小基于 的objectSize字段ClassObjectobjectSize设置在computeFieldOffsets(第 3543 行)。如果您在此函数中找到 fieldOffset 递增的每个实例,您会注意到它始终以 4 个字节的步长递增。

短字段占用 4 个字节。

于 2012-10-26T04:02:25.947 回答
2

(将是一个评论,但它太长了。)

将 4 字节字段用于“短”本地变量是相当常规的,因为 JVM 在概念上是一台具有 4 字节寄存器的机器,并且所有其他垃圾都在堆栈帧中并没有太大区别。

例如字段,它可能取决于节省存储与必须花费周期进行加宽和对齐的权衡——加宽通常会花费一个小周期,即使在所谓的边界对齐“不可知”的架构上,通常也会有惩罚对于越界访问,因此“打包”字段而不首先重新排列它们以保持字/双字边界可能会降低性能。

因此,如果 JVM 选择“打包”字段,则通常需要重新排列。幼稚的 JVM 将避免重新排列,因为这使得 JVM 的几个方面更简单,但是(作为一个示例)在 AS/400 上,我们发现积极地重新排序和打包实例字段对于需要存储的应用程序的性能提高了 30%。

我从来没有看过达尔维克的内脏。标准 Sun 派生的 JVM 在历史上(没有查看最近的任何内容)依赖于 .class 文件中事物的布局/顺序,因此“自然”不适合重新排序。但是 Dalvik 重新构成了 .class 文件,因此可以更好地进行实例字段重新排序。

请注意,要测试 Dalvik 打包字段的假设,short您必须创建一个具有几个背靠背实例字段的类,然后确定生成的对象大小。另外(假设在第一种情况下看到打包),创建一个带有shortint(或可能long)字段交错的类,以查看 Dalvik 是否对它们重新排序以实现打包。

于 2012-10-25T19:38:19.463 回答