digitalmars.D - Class Instance allocations
- bearophile <bearophileHUGS lycos.com> Jan 11 2010
- Justin Johansson <no spam.com> Jan 13 2010
- "Robert Jacques" <sandford jhu.edu> Jan 13 2010
- Justin Johansson <no spam.com> Jan 13 2010
- bearophile <bearophileHUGS lycos.com> Jan 13 2010
- bearophile <bearophileHUGS lycos.com> Jan 13 2010
- bearophile <bearophileHUGS lycos.com> Jan 14 2010
- "Simen kjaeraas" <simen.kjaras gmail.com> Jan 13 2010
- "Steven Schveighoffer" <schveiguy yahoo.com> Jan 14 2010
This page says "The pointer returned from new() must be to memory aligned to the default alignment. This is 8 on win32 systems.": http://www.digitalmars.com/d/2.0/memory.html Is that true? Is this required by the tag bits added by the GC scans? Does std.c.stdlib.malloc always return aligned to 8 on Windows? Below in the same page, in the Mark/Release section: class Foo { ... new(size_t sz) { void *p; p = &buffer[bufindex]; bufindex += sz; if (bufindex > buffer.length) throw new OutOfMemory; return p; } ... If sz is not a multiple of 8 then new() can return a pointer not aligned to 8: import std.outofmemory: OutOfMemoryException; import std.gc: addRange, removeRange; import std.c.stdlib: malloc, free; import std.c.stdio: printf; class Foo { static void[] buffer; static int bufIndex; static const int bufSize = 100; int x; //********** static this() { void* p = malloc(bufSize); if (!p) throw new OutOfMemoryException; addRange(p, p + bufSize); buffer = p[0 .. bufSize]; } static ~this() { if (buffer.length) { removeRange(buffer.ptr); free(buffer.ptr); buffer = null; } } new(size_t sz) { void* p = &buffer[bufIndex]; bufIndex += sz; if (bufIndex > buffer.length) throw new OutOfMemoryException; printf("%d %d\n", cast(size_t)p, cast(size_t)p % 8); // ****** return p; } delete(void* p) { assert(0); } static int mark() { return bufIndex; } static void release(int i) { bufIndex = i; } } void main() { int m = Foo.mark(); Foo f1 = new Foo; // allocate Foo f2 = new Foo; // allocate Foo.release(m); // deallocate f1 and f2 } Output, f2 reference is now always aligned to 4 bytes: 1382368 0 1382380 4 So, does the new() in this class (that has that extra "x" field) need to be fixed to be sure the pointers it returns are aligned to 8? The Foo class in the Mark/Release section has some other little bugs, that I think I have fixed here. D docs need something like the Andrei's book machinery, where D code snippets are actually run (Python docs too run their snippets). Bye, bearophile
Jan 11 2010
I understand your quandary. For me "Win32" == "32 bits" == "4 bytes" == "sizeof(ubiquitous machine register)". So why on earth, since Visual Studio 2001 (and before?), was the default alignment set to 8 bytes for the M$ C/C++ compiler code generation option? This I just do not understand (so, of course, enlightenment is welcome). Beers for the New Years, Justin Johansson bearophile wrote:This page says "The pointer returned from new() must be to memory aligned to the default alignment. This is 8 on win32 systems.": http://www.digitalmars.com/d/2.0/memory.html Is that true? Is this required by the tag bits added by the GC scans? Does std.c.stdlib.malloc always return aligned to 8 on Windows? Below in the same page, in the Mark/Release section: class Foo { ... new(size_t sz) { void *p; p = &buffer[bufindex]; bufindex += sz; if (bufindex > buffer.length) throw new OutOfMemory; return p; } ... If sz is not a multiple of 8 then new() can return a pointer not aligned to 8: import std.outofmemory: OutOfMemoryException; import std.gc: addRange, removeRange; import std.c.stdlib: malloc, free; import std.c.stdio: printf; class Foo { static void[] buffer; static int bufIndex; static const int bufSize = 100; int x; //********** static this() { void* p = malloc(bufSize); if (!p) throw new OutOfMemoryException; addRange(p, p + bufSize); buffer = p[0 .. bufSize]; } static ~this() { if (buffer.length) { removeRange(buffer.ptr); free(buffer.ptr); buffer = null; } } new(size_t sz) { void* p = &buffer[bufIndex]; bufIndex += sz; if (bufIndex > buffer.length) throw new OutOfMemoryException; printf("%d %d\n", cast(size_t)p, cast(size_t)p % 8); // ****** return p; } delete(void* p) { assert(0); } static int mark() { return bufIndex; } static void release(int i) { bufIndex = i; } } void main() { int m = Foo.mark(); Foo f1 = new Foo; // allocate Foo f2 = new Foo; // allocate Foo.release(m); // deallocate f1 and f2 } Output, f2 reference is now always aligned to 4 bytes: 1382368 0 1382380 4 So, does the new() in this class (that has that extra "x" field) need to be fixed to be sure the pointers it returns are aligned to 8? The Foo class in the Mark/Release section has some other little bugs, that I think I have fixed here. D docs need something like the Andrei's book machinery, where D code snippets are actually run (Python docs too run their snippets). Bye, bearophile
Jan 13 2010
On Wed, 13 Jan 2010 10:29:35 -0500, Justin Johansson <no spam.com> wrote:I understand your quandary. For me "Win32" == "32 bits" == "4 bytes" == "sizeof(ubiquitous machine register)". So why on earth, since Visual Studio 2001 (and before?), was the default alignment set to 8 bytes for the M$ C/C++ compiler code generation option? This I just do not understand (so, of course, enlightenment is welcome). Beers for the New Years, Justin Johansson
If I recall correctly, doubles require 8-byte alignment. So you object therefore must require 8-byte alignment.
Jan 13 2010
Robert Jacques wrote:On Wed, 13 Jan 2010 10:29:35 -0500, Justin Johansson <no spam.com> wrote:I understand your quandary. For me "Win32" == "32 bits" == "4 bytes" == "sizeof(ubiquitous machine register)". So why on earth, since Visual Studio 2001 (and before?), was the default alignment set to 8 bytes for the M$ C/C++ compiler code generation option? This I just do not understand (so, of course, enlightenment is welcome). Beers for the New Years, Justin Johansson
If I recall correctly, doubles require 8-byte alignment. So you object therefore must require 8-byte alignment.
Instances of my Foo class require 17 bytes so therefore all objects require 17 byte alignment. But for my Bar class it's 42. ???
Jan 13 2010
Justin Johansson:So why on earth, since Visual Studio 2001 (and before?), was the default alignment set to 8 bytes for the M$ C/C++ compiler code generation option?
Maybe because for compatibility reasons they can't require a 16 bytes alignment (as OS X does, I think) as SSE registers appreciate.Is that true? Is this required by the tag bits added by the GC scans? Does std.c.stdlib.malloc always return aligned to 8 on Windows?<<
And no one has given me such answers yet. And currently the D GC seems to always return aligned to 16 bytes (even chunks of memory smaller than 16 bytes). Bye, bearophile
Jan 13 2010
bearophile:And currently the D GC seems to always return aligned to 16 bytes (even chunks of memory smaller than 16 bytes).<
I hope to be wrong :-)
Jan 13 2010
On 01/13/2010 06:18 PM, bearophile wrote:bearophile:And currently the D GC seems to always return aligned to 16 bytes (even chunks of memory smaller than 16 bytes).<
I hope to be wrong :-)
it somewhere around here.
Jan 13 2010
Steven Schveighoffer:I'm not sure if SSE register requires alignment. Typically on systems that do not support loading from a byte-aligned memory segment will throw a bus error if you try to do it.
I think SSE registers require 8 byte alignment, but some of their operations are faster with data aligned on 16 bytes. In future this 16 byte alignment requirement will probably be slowly dropped (already partially dropped in core i7). At that point the 16 byte alignment of the D GC can become overkill.I think the reason the allocator must return 8-byte aligned memory is because the allocator doesn't know what you're going to put in there, so it must handle the worst case scenario (doubles).
I think it may also be a matter of tag bits added to pointers by the mark phase of the GC. I think two bits may suffice, so I don't know why the alignment to 8. Anyway, the new() method in the class I've shown at the top of this thread is wrong then, because sometimes it returns aligned to 4. It needs some extra machinery to fix this. Bye, bearophile
Jan 14 2010
Justin Johansson <no spam.com> wrote:If I recall correctly, doubles require 8-byte alignment. So you object therefore must require 8-byte alignment.
Instances of my Foo class require 17 bytes so therefore all objects require 17 byte alignment. But for my Bar class it's 42. ???
If a member of your class requires n-byte alignment, your class will require (k*n)-byte alignment (where k is a positive integer), to ensure the member has its required alignment. Example: doubles require 8-byte alignment. You create class foo { double bar; }. If your foo is offset by 2 bytes from an 8-byte border, so is bar, and thus its alignment is broken. -- Simen
Jan 13 2010
On Wed, 13 Jan 2010 12:16:30 -0500, bearophile <bearophileHUGS lycos.com> wrote:Justin Johansson:So why on earth, since Visual Studio 2001 (and before?), was the default alignment set to 8 bytes for the M$ C/C++ compiler code generation option?
Maybe because for compatibility reasons they can't require a 16 bytes alignment (as OS X does, I think) as SSE registers appreciate.
It depends on the architecture/register. On most chips, if you load a register from a segment of memory, that memory has to be n-byte aligned where n is the number of bytes for the register. But there are exceptions. I'm not sure if SSE register requires alignment. Typically on systems that do not support loading from a byte-aligned memory segment will throw a bus error if you try to do it.Is that true? Is this required by the tag bits added by the GC scans? Does std.c.stdlib.malloc always return aligned to 8 on Windows?<<
And no one has given me such answers yet. And currently the D GC seems to always return aligned to 16 bytes (even chunks of memory smaller than 16 bytes).
I would guess that pointers on a 32-bit architecture need to be 4-byte aligned, otherwise, a struct like this: struct S { int *x; int *y; } would have to be minimum of 16 bytes! I think the reason the allocator must return 8-byte aligned memory is because the allocator doesn't know what you're going to put in there, so it must handle the worst case scenario (doubles). BTW, 16 bytes is the minimum size the GC returns, and I think it's a somewhat arbitrary decision. The minimum you could possibly return is 8 bytes, and it becomes a judgement call that depends on other factors if you want to increase the minimum size (less overhead per block vs. more wasted space). -Steve
Jan 14 2010









Justin Johansson <no spam.com> 