On 1/4/23 10:48, H. S. Teoh wrote:

> Allocations are not necessarily consecutive; the GC may have its own
> strategy of allocation that doesn't follow a linear sequence.

That was one of my guesses. So, I put the objects into a 2-length static array but the difference was still 0x20. (?)

> Furthermore, GC-allocated blocks may be larger than the request size
> because there may be some extra management information stored in the
> block (but outside the pointer range returned).

Good point. I think the minimum size of a dynamically allocated memory of the current GC implementation is 32 bytes.

I've just realized that I was confusing myself by thinking the object pointer that cast(void*) produces was the first member's address. I was wrong: That is the address of the first of the two hidden members (the vtbl pointer and the monitor).

My current guess is, although it could be a void*, the alignment of the first of those hidden members is 16.

Now that I have a more correct understanding, the following program prints those hidden members. One of the examples shows the monitor of an object used with 'synchronized' is non-null.

import std.stdio, std.traits;

class MyClass {
    char[1] c;
}

void main() {
    writeln(" Size  Alignment  Type\n",
            "=========================");

    size_t size = __traits(classInstanceSize, MyClass);
    size_t alignment = classInstanceAlignment!MyClass;
    writefln("%4s%8s      %s",size, alignment, MyClass.stringof);

    // Apologies for using lower-cased variable names. :)
    auto a = new MyClass();
    auto b = new MyClass();

    printObject!a;
    printObject!b;

    auto withMonitor = new MyClass();

    synchronized (withMonitor) {
        // This object's "hidden 1" (the monitor) will not be 'null'
        printObject!withMonitor;
    }

    // This object's "hidden 0" (vtbl pointer) will be different:
    class SubClass : MyClass {
    }
    auto sub = new SubClass();
    printObject!sub;
}

void printObject(alias obj)() {
    writeln("\n");
    writeln("name        : ", obj.stringof);

    const addr = cast(void*)obj;
    writeln("address     : ", addr);
    writeln("hidden 0    : ", hiddenValue(addr, 0));
    writeln("hidden 1    : ", hiddenValue(addr, 1));
}

void* hiddenValue(const(void)* obj, size_t index) {
    alias HiddenType = void*;
    auto ptrToHiddens = cast(HiddenType[2]*)obj;
    return (*ptrToHiddens)[index];
}

Here is the output:

 Size  Alignment  Type
=========================
  17       8      MyClass


name        : a
address     : 7F4009D48000
hidden 0    : 558A1E172520
hidden 1    : null


name        : b
address     : 7F4009D48020
hidden 0    : 558A1E172520
hidden 1    : null


name        : withMonitor
address     : 7F4009D48040
hidden 0    : 558A1E172520
hidden 1    : 558A20164B80  <-- non-null monitor


name        : sub
address     : 7F4009D48060
hidden 0    : 558A1E172630  <-- Different vtbl for sub-class
hidden 1    : null

Ali

Reply via email to