如何Java对象在内存中排列在Android?排列、对象、内存、Java

2023-09-05 01:57:24 作者:妳猜我們的結局,

我相当熟悉的物体在热点堆的布局,但没有那么多为Android。

例如,在一个32位的HotSpot JVM中,在堆上一个对象被实现为一个8字节的标题,随后的对象的字段(一个字节用于布尔,四字节为基准,和其他一切如预期),奠定了在一些特定的顺序(有一些特殊的规则,从超类的字段),并填充出的8个字节的倍数。

我已经做了一些研究,但我找不到任何Android的具体信息。

(我感兴趣的是优化了一些非常广泛的数据结构,以减少内存消耗在Android上。)

解决方案

的Dalvik / VM / OO / Object.h 为您提供帮助。注释为结构对象说:

  / *
 *有三种类型的对象:
 * Class对象 -  java.lang.Class的一个实例
 *数组对象 - 一个新阵指令创建的对象
 *数据对象 - 一个对象,它既不是上述的
 *
 *我们还定义了String对象。在present他们相当于
 *数据对象,但可能会改变。 (无论哪种方式,他们做了一些
 * code更明显。)
 *
 *所有的对象都有一个对象头,后跟特定类型的数据。
 * /
 

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

 结构ArrayObject的:对象{
    / *元素的数目; INIT *后不可改变/
    U4长度;

    / *
     *数组内容;实际尺寸(长* sizeof的(类型))。这是
     *声明为U8,使编译器插入任何必要的填充
     *(例如用于EABI);实际的分配可能比8个字节以下。
     * /
    U8内容[1];
};
 
图文详解Java对象内存布局

有关阵列,宽度在 VM / OO / Array.cpp 。布尔是宽1,对象有的sizeof(对象*)的长度(通常为4),和所有其他原始类型都有自己的预期(包装)的长度。

数据对象是非常简单的:

  / *
 *数据对象有一个对象头后面的实例数据。
 * /
结构数据对象:对象{
    / *变移位#of U4插槽; U8采用2个插槽* /
    U4 instanceData [1];
};
 

数据对象(所有非Class类的实例)的布局由 computeFieldOffsets 在 VM / OO / Class.cpp 。根据该意见有:

  / *
 *指定实例字段U4插槽。
 *
 *实例场区的顶部部分由超类所占据
 *领域,通过为此类领域的底部。
 *
 *长和双领域占据两个相邻的插槽。在一些
 *架构,64位的数量必须为64位对齐,所以我们需要
 *安排字段(或引入填充),以确保这一点。我们假设
 *最上面的超类(即对象)的字段是64位对齐,因此
 *我们只能保证偏移量为甚至。为了避免浪费空间,
 *我们要移动非基准32位字段为空白,而不是
 *创建垫的话。
 *
 *在最坏的情况下,我们将浪费4个字节,但由于对象是
 *分配在> = 64位的边界,这些字节很可能是反正浪费
 *(假设这是最派生类)。
 *
 *垫话是不是重新psented在场上表$ P $,所以外地表
 *本身不改变大小。
 *
 *字段时隙的数目确定物体的大小,因此,我们
 *设置在这里了。
 *
 *这个功能感觉有点复杂得多,我想,但它
 *有移动的最小可能的字段集的属性,该属性
 *应该减少加载类所需的时间。
 *
 *注:参考字段*必须*是第一位的,或precacheReferenceOffsets()
 *将打破。
 * /
 

所以,超类字段来的第一(照常),接着参照型字段,随后是一个32位字段(如果有的话,并且如果填充是必需的,因为有32位参考场奇数)其次是64位字段。常规32位字段遵循。请注意,所有字段都是32位或64位(短元是填补空白)。特别是,在这个时候,在VM不存储字节/焦炭使用少于4个字节,尽管它当然可以在理论上支持这一点。/短路/布尔字段

请注意,所有这一切是基于阅读的Dalvik源$ C ​​$ C作为提交 43241340 (2013年2月6日)。由于虚拟机这方面似乎并没有被公开记录在案,你不应该依赖这是虚拟机的对象布局的稳定描述:它可能会随时间而改变

I'm fairly familiar with the layout of objects on the heap in HotSpot, but not so much for Android.

For example, in a 32-bit HotSpot JVM, an object on the heap is implemented as an 8-byte header, followed by the object's fields (one byte for boolean, four bytes for a reference, and everything else as expected), laid out in some specific order (with some special rules for fields from superclasses), and padded out to a multiple of 8 bytes.

I've done some research, but I can't find any Android-specific information.

(I'm interested in optimizing some extremely widely used data structures to minimize memory consumption on Android.)

解决方案

dalvik/vm/oo/Object.h is your friend here. The comment for struct Object says:

/*
 * 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 objects are special; their layout is defined by the ClassObject struct in Object.h. Array objects are simple:

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];
};

For arrays, the widths are in vm/oo/Array.cpp. Booleans are width 1, objects have sizeof(Object*) length (usually 4), and all other primitive types have their expected (packed) length.

Data objects are really simple:

/*
 * 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];
};

The layout of a DataObject (all non-Class class instances) is governed by computeFieldOffsets in vm/oo/Class.cpp. According to the comment there:

/*
 * 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.
 */

So, superclass fields come first (as usual), followed by reference-type fields, followed by a single 32-bit field (if available, and if padding is required because there's an odd number of 32-bit reference fields) followed by 64-bit fields. Regular 32-bit fields follow. Note that all fields are 32-bit or 64-bit (shorter primitives are padded). In particular, at this time, the VM does not store byte/char/short/boolean fields using less than 4 bytes, though it certainly could support this in theory.

Note that all of this is based on reading the Dalvik source code as of commit 43241340 (Feb 6, 2013). Since this aspect of the VM doesn't appear to be publically documented, you should not rely on this to be a stable description of the VM's object layout: it may change over time.