Java对象在Android上的内存中是如何布局的?

2022-09-02 01:43:43

我对HotSpot中堆上对象的布局相当熟悉,但对于Android来说却不那么熟悉。

例如,在 32 位 HotSpot JVM 中,堆上的对象实现为 8 字节标头,后跟对象的字段(一个字节用于引用,四个字节用于引用,其他所有内容按预期),按某种特定顺序布局(对来自超类的字段有一些特殊规则),并填充到 8 个字节的倍数。boolean

我做了一些研究,但我找不到任何Android特定的信息。

(我有兴趣优化一些非常广泛使用的数据结构,以最大限度地减少Android上的内存消耗。


答案 1

dalvik/vm/oo/Object.h是你在这里的朋友。的评论说:struct Object

/*
 * There are three types of objects:
 *  Class objects - an instance of java.lang.Class
 *  Array objects - an object created with a "new array" instruction
 *  Data objects - an object that is neither of the above
 *
 * We also define String objects.  At present they're equivalent to
 * DataObject, but that may change.  (Either way, they make some of the
 * code more obvious.)
 *
 * All objects have an Object header followed by type-specific data.
 */

java.lang.Class对象是特殊的;它们的布局由 中的结构定义。数组对象很简单:ClassObjectObject.h

struct ArrayObject : Object {
    /* number of elements; immutable after init */
    u4              length;

    /*
     * Array contents; actual size is (length * sizeof(type)).  This is
     * declared as u8 so that the compiler inserts any necessary padding
     * (e.g. for EABI); the actual allocation may be smaller than 8 bytes.
     */
    u8              contents[1];
};

对于数组,宽度以 为单位。布尔值的宽度为 1,对象的长度为 4(通常为 4),所有其他基元类型具有其预期(打包)长度。vm/oo/Array.cppsizeof(Object*)

数据对象非常简单:

/*
 * Data objects have an Object header followed by their instance data.
 */
struct DataObject : Object {
    /* variable #of u4 slots; u8 uses 2 slots */
    u4              instanceData[1];
};

(所有非 Class 类实例)的布局由 in 控制。根据那里的评论:DataObjectcomputeFieldOffsetsvm/oo/Class.cpp

/*
 * Assign instance fields to u4 slots.
 *
 * The top portion of the instance field area is occupied by the superclass
 * fields, the bottom by the fields for this class.
 *
 * "long" and "double" fields occupy two adjacent slots.  On some
 * architectures, 64-bit quantities must be 64-bit aligned, so we need to
 * arrange fields (or introduce padding) to ensure this.  We assume the
 * fields of the topmost superclass (i.e. Object) are 64-bit aligned, so
 * we can just ensure that the offset is "even".  To avoid wasting space,
 * we want to move non-reference 32-bit fields into gaps rather than
 * creating pad words.
 *
 * In the worst case we will waste 4 bytes, but because objects are
 * allocated on >= 64-bit boundaries, those bytes may well be wasted anyway
 * (assuming this is the most-derived class).
 *
 * Pad words are not represented in the field table, so the field table
 * itself does not change size.
 *
 * The number of field slots determines the size of the object, so we
 * set that here too.
 *
 * This function feels a little more complicated than I'd like, but it
 * has the property of moving the smallest possible set of fields, which
 * should reduce the time required to load a class.
 *
 * NOTE: reference fields *must* come first, or precacheReferenceOffsets()
 * will break.
 */

因此,超类字段排在第一位(像往常一样),然后是引用类型字段,然后是单个 32 位字段(如果可用,并且由于存在奇数个 32 位引用字段而需要填充),然后是 64 位字段。常规 32 位字段紧随其后。请注意,所有字段都是 32 位或 64 位(填充较短的基元)。特别是,此时,VM 不使用少于 4 个字节来存储字节/字符/短/布尔字段,尽管它在理论上肯定可以支持这一点。

请注意,所有这些都是基于在提交(2013 年 2 月 6 日)时阅读 Dalvik 源代码。由于 VM 的这一方面似乎没有公开记录,因此不应依赖此作为 VM 对象布局的稳定描述:它可能会随时间而变化。43241340


答案 2

推荐