Thread overview
Garbage collection from associative arrays
Mar 25, 2006
Sebastian Beschke
Mar 25, 2006
Sebastian Beschke
Mar 25, 2006
Oskar Linde
Mar 25, 2006
Sean Kelly
Mar 26, 2006
Thomas Kuehne
March 25, 2006
The following program creates a couple of instances of a class and stores them in an associative array. It then tries to periodically access those instances via the associative array, performing garbage collects in between.

As it appears, a fullCollect will destroy the objects, even though they are stored in an associative array. This leads to an access violation in the second loop.

Is this a known bug? Can it be fixed? Are there any workarounds?

Regards, Sebastian



Output on my machine:

Loading...
class created
class created
class created
97
98
99
class killed (99)
class killed (98)
class killed (97)
Error: Access Violation


Program code:

private {
	import std.gc;
	import std.stdio;
}


class SomeClass {
	this(char value) {
		writefln("class created");
		_value = value;
	}

	~this()
	{
		writefln("class killed (%d)", _value);
	}

	char value() {
		return _value;
	}


	private {
		char _value;
	}
}

static char[] allChars = [
	'a', 'b', 'c'
	];


SomeClass[char] _chars;

void _realLoad() {
	writefln("Loading...");
	foreach(char ch; allChars) {
		_chars[ch] = new SomeClass(ch);
    }
}



int main(char[][] args)
{
	bool done = false;
	_realLoad();

	while(!done)
	{
		foreach(char ch; allChars) {
			SomeClass obj = _chars[ch];
			writefln("%d", obj.value);
		}
		std.gc.fullCollect();
	}
}
March 25, 2006
Well, I found a workaround: Just modify the index type of the associative array to int.


Sebastian Beschke schrieb:
> The following program creates a couple of instances of a class and stores them in an associative array. It then tries to periodically access those instances via the associative array, performing garbage collects in between.
> 
> As it appears, a fullCollect will destroy the objects, even though they are stored in an associative array. This leads to an access violation in the second loop.
> 
> Is this a known bug? Can it be fixed? Are there any workarounds?
> 
> Regards, Sebastian
> 
> 
> 
> Output on my machine:
> 
> Loading...
> class created
> class created
> class created
> 97
> 98
> 99
> class killed (99)
> class killed (98)
> class killed (97)
> Error: Access Violation
> 
> 
> Program code:
> 
> private {
> 	import std.gc;
> 	import std.stdio;
> }
> 
> 
> class SomeClass {
> 	this(char value) {
> 		writefln("class created");
> 		_value = value;
> 	}
> 
> 	~this()
> 	{
> 		writefln("class killed (%d)", _value);
> 	}
> 
> 	char value() {
> 		return _value;
> 	}
> 
> 
> 	private {
> 		char _value;
> 	}
> }
> 
> static char[] allChars = [
> 	'a', 'b', 'c'
> 	];
> 
> 
> SomeClass[char] _chars;
> 
> void _realLoad() {
> 	writefln("Loading...");
> 	foreach(char ch; allChars) {
> 		_chars[ch] = new SomeClass(ch);
>     }
> }
> 
> 
> 
> int main(char[][] args)
> {
> 	bool done = false;
> 	_realLoad();
> 
> 	while(!done)
> 	{
> 		foreach(char ch; allChars) {
> 			SomeClass obj = _chars[ch];
> 			writefln("%d", obj.value);
> 		}
> 		std.gc.fullCollect();
> 	}
> }
March 25, 2006
Sebastian Beschke wrote:

> Sebastian Beschke schrieb:
>> The following program creates a couple of instances of a class and stores them in an associative array. It then tries to periodically access those instances via the associative array, performing garbage collects in between.
>> 
>> As it appears, a fullCollect will destroy the objects, even though they are stored in an associative array. This leads to an access violation in the second loop.
>> 
>> Is this a known bug? Can it be fixed? Are there any workarounds?
>
> Well, I found a workaround: Just modify the index type of the associative array to int.

Yeah. The error lies in the AA implementation. The pointers are not stored on the correct alignment. Each node of the AA is allocated in the following way:

e = cast(aaA *) cast(void*) new byte[aaA.sizeof + keysize + valuesize];

The aaA struct contains two pointers (left&right) and a uint hash. That is 12 bytes on a 32 bit machine. If keysize isn't divisible by 4, the pointers stored as values will not be 4-byte aligned.

/Oskar
March 25, 2006
Sebastian Beschke wrote:
> The following program creates a couple of instances of a class and
> stores them in an associative array. It then tries to periodically
> access those instances via the associative array, performing garbage
> collects in between.
> 
> As it appears, a fullCollect will destroy the objects, even though they
> are stored in an associative array. This leads to an access violation in
> the second loop.
> 
> Is this a known bug? Can it be fixed? Are there any workarounds?

I ran into something similar to this when first writing Ares, as I was using a map to store thread handles.  Basically, when a value is being added to the AA, the AA is first modified to hold some uninitialized data, then memory is allocated, then everything is initialized.  As it's possible this is the same problem, you may want to check out my fix here:

http://svn.dsource.org/projects/ares/trunk/src/dmdrt/aaA.d

Look for "better to fully construct" as a portion of the comment documenting the change.


Sean
March 26, 2006
Sebastian Beschke schrieb am 2006-03-25:
> The following program creates a couple of instances of a class and stores them in an associative array. It then tries to periodically access those instances via the associative array, performing garbage collects in between.
>
> As it appears, a fullCollect will destroy the objects, even though they are stored in an associative array. This leads to an access violation in the second loop.
>
> Is this a known bug? Can it be fixed? Are there any workarounds?
>
> Regards, Sebastian
>
>
>
> Output on my machine:
>
> Loading...
> class created
> class created
> class created
> 97
> 98
> 99
> class killed (99)
> class killed (98)
> class killed (97)
> Error: Access Violation
>
>
> Program code:
>
> private {
> 	import std.gc;
> 	import std.stdio;
> }
>
>
> class SomeClass {
> 	this(char value) {
> 		writefln("class created");
> 		_value = value;
> 	}
> 
> 	~this()
> 	{
> 		writefln("class killed (%d)", _value);
> 	}
> 
> 	char value() {
> 		return _value;
> 	}
> 
> 
> 	private {
> 		char _value;
> 	}
> }
>
> static char[] allChars = [
> 	'a', 'b', 'c'
> 	];
>
>
> SomeClass[char] _chars;
> 
> void _realLoad() {
> 	writefln("Loading...");
> 	foreach(char ch; allChars) {
> 		_chars[ch] = new SomeClass(ch);
>     }
> }
>
>
>
> int main(char[][] args)
> {
> 	bool done = false;
> 	_realLoad();
> 
> 	while(!done)
> 	{
> 		foreach(char ch; allChars) {
> 			SomeClass obj = _chars[ch];
> 			writefln("%d", obj.value);
> 		}
> 		std.gc.fullCollect();
> 	}
> }

Added to DStress as http://dstress.kuehne.cn/run/a/associative_array_19_A.d http://dstress.kuehne.cn/run/a/associative_array_19_B.d http://dstress.kuehne.cn/run/a/associative_array_19_C.d http://dstress.kuehne.cn/run/a/associative_array_19_D.d http://dstress.kuehne.cn/run/a/associative_array_19_E.d http://dstress.kuehne.cn/run/a/associative_array_19_F.d http://dstress.kuehne.cn/run/a/associative_array_19_G.d http://dstress.kuehne.cn/run/a/associative_array_19_H.d http://dstress.kuehne.cn/run/a/associative_array_19_I.d http://dstress.kuehne.cn/run/a/associative_array_19_J.d http://dstress.kuehne.cn/run/a/associative_array_19_K.d http://dstress.kuehne.cn/run/a/associative_array_19_L.d http://dstress.kuehne.cn/run/a/associative_array_19_M.d http://dstress.kuehne.cn/run/a/associative_array_19_N.d http://dstress.kuehne.cn/run/a/associative_array_19_O.d http://dstress.kuehne.cn/run/a/associative_array_19_P.d http://dstress.kuehne.cn/run/a/associative_array_19_Q.d http://dstress.kuehne.cn/run/a/associative_array_19_R.d http://dstress.kuehne.cn/run/a/associative_array_19_S.d http://dstress.kuehne.cn/run/a/associative_array_19_T.d http://dstress.kuehne.cn/run/a/associative_array_19_U.d http://dstress.kuehne.cn/run/a/associative_array_19_V.d http://dstress.kuehne.cn/run/a/associative_array_19_W.d http://dstress.kuehne.cn/run/a/associative_array_19_X.d http://dstress.kuehne.cn/run/a/associative_array_19_Y.d http://dstress.kuehne.cn/run/a/associative_array_19_Z.d

Thomas