www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Behaviour of fullCollect() depends on a printf in the constructor...

reply Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
Hi,

Being new to garbage collection, I find the following puzzling. In the 
code below, where two objects refer to each other, main() has no 
references to any objects anymore when fullCollect() is run, but none of 
the objects are deleted. However, when we put a printf in the 
constructor for B (line 24), the behaviour changes to the expected 
behaviour: all objects are deleted before fullCollect() returns. Please 
explain this to me :-)

Bastiaan.


#//file: gctest.d
#
#class A
#{
#	B b;
#	
#	this()
#	{
#		b = new B(this);
#		printf("A constructed.\n");
#	}
#	~this()
#	{
#		printf("A destructed.\n");
#	}
#}
#
#class B
#{
#	this(Object owner)
#	{
#		_owner = owner;
#		// uncomment the following and the GC runs as expected.
#//		printf("B constructed.\n");
#	}
#	~this()
#	{
#		printf("B destructed.\n");
#	}
#private:
#	Object _owner;
#}
#
#import std.gc;
#
#void main()
#{
#	A a = new A;
#	a = null;
#	printf("Running fullCollect()...\n");
#	fullCollect();
#	printf("Done collecting.\n");
#}
Aug 29 2004
parent reply Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
[Additional info. Cross-posting to D.bugs as this is probably a bug.]

Bastiaan Veelo wrote:
 Hi,
 
 Being new to garbage collection, I find the following puzzling. In the 
 code below, where two objects refer to each other, main() has no 
 references to any objects anymore when fullCollect() is run, but none of 
 the objects are deleted. However, when we put a printf in the 
 constructor for B (line 24), the behaviour changes to the expected 
 behaviour: all objects are deleted before fullCollect() returns. Please 
 explain this to me :-)
 
 Bastiaan.
 
 
 #//file: gctest.d
 #
 #class A
 #{
 #    B b;
 #   
 #    this()
 #    {
 #        b = new B(this);
 #        printf("A constructed.\n");
 #    }
 #    ~this()
 #    {
 #        printf("A destructed.\n");
 #    }
 #}
 #
 #class B
 #{
 #    this(Object owner)
 #    {
 #        _owner = owner;
 #        // uncomment the following and the GC runs as expected.
 #//        printf("B constructed.\n");
 #    }
 #    ~this()
 #    {
 #        printf("B destructed.\n");
 #    }
 #private:
 #    Object _owner;
 #}
 #
 #import std.gc;
 #
 #void main()
 #{
 #    A a = new A;
 #    a = null;
 #    printf("Running fullCollect()...\n");
 #    fullCollect();
 #    printf("Done collecting.\n");
 #}

Additional info: Run on linux, compiled with dmd-0.100, the output of the above code is A constructed. Running fullCollect()... Done collecting. B destructed. A destructed. With the printf you get the expected time of destruction: B constructed. A constructed. Running fullCollect()... B destructed. A destructed. Done collecting. Bastiaan.
Aug 30 2004
parent reply Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
[Even more info.]

Bastiaan Veelo wrote:
 [Additional info. Cross-posting to D.bugs as this is probably a bug.]
 
 Bastiaan Veelo wrote:
 
 Hi,

 Being new to garbage collection, I find the following puzzling. In the 
 code below, where two objects refer to each other, main() has no 
 references to any objects anymore when fullCollect() is run, but none 
 of the objects are deleted. However, when we put a printf in the 
 constructor for B (line 24), the behaviour changes to the expected 
 behaviour: all objects are deleted before fullCollect() returns. 
 Please explain this to me :-)

 Bastiaan.


 #//file: gctest.d
 #
 #class A
 #{
 #    B b;
 #   #    this()
 #    {
 #        b = new B(this);
 #        printf("A constructed.\n");
 #    }
 #    ~this()
 #    {
 #        printf("A destructed.\n");
 #    }
 #}
 #
 #class B
 #{
 #    this(Object owner)
 #    {
 #        _owner = owner;
 #        // uncomment the following and the GC runs as expected.
 #//        printf("B constructed.\n");
 #    }
 #    ~this()
 #    {
 #        printf("B destructed.\n");
 #    }
 #private:
 #    Object _owner;
 #}
 #
 #import std.gc;
 #
 #void main()
 #{
 #    A a = new A;
 #    a = null;
 #    printf("Running fullCollect()...\n");
 #    fullCollect();
 #    printf("Done collecting.\n");
 #}

Additional info: Run on linux, compiled with dmd-0.100, the output of the above code is A constructed. Running fullCollect()... Done collecting. B destructed. A destructed. With the printf you get the expected time of destruction: B constructed. A constructed. Running fullCollect()... B destructed. A destructed. Done collecting. Bastiaan.

When compiled with gdc release 1f, which is based on the 0.82 frontend, this code executes as expected in both cases; no bugs revealed. Bastiaan.
Aug 30 2004
parent "Walter" <newshound digitalmars.com> writes:
What happens is the gc scans the stack and registers for references to the
heap. There can be 'left over' values on the stack and registers that are
detected this way, which will hold on to the objects in the heap. The call
to printf() likely overwrites those left over values, and so the objects get
collected.

The bottom line is you shouldn't write gc code as if it had deterministic
finalization. If that's what you need, use auto classes and RAII techniques.
Aug 30 2004