[疑难] D的gc是怎么工作的?

qiezi 2007-05-15
刚看了dstring的实现,有一点小疑问:
	static string opCall(char[] s)
	{
		if(s.length > MAX_LENGTH)
			errortoolong();
		
		size_t sct = TYPE_UTF8;
		
		foreach(dchar ch; s)
		{
			size_t x;
			x = smallestCharType(ch);
			if(x > sct)
			{
				sct = x;
				if(TYPE_UTF32 == x)
					break;
			}
		}
		
		string result;
		
		switch(sct)
		{
			case TYPE_UTF32:
				{
					dchar[] ds;
					ds = std.utf.toUTF32(s);
					result._dptr = ds.ptr;
					result._len = ds.length;
					result._len |= TYPE_UTF32;
				}
				break;
			
			case TYPE_UTF16:
				{
					wchar[] ws;
					ws = std.utf.toUTF16(s);
					result._wptr = ws.ptr;
					result._len = ws.length;
					result._len |= TYPE_UTF16;
				}
				break;
			
			default:
				result._cptr = s.ptr;
				result._len = s.length;
				result._len |= TYPE_UTF8;
		}
		
		return result;
	}

我的想法是这里在栈上分配的ds/ws可能在某次GC以后被释放掉,然后string里的指针将指向无效空间(当然是GC堆上的),虽然可以读取,但如果被后面的。通常在GC后再分配空间将是刚刚释放掉的那些,所以如果循环执行fullCollect再分配,将分配到同一块内存,这时候将使dstring显现出一个BUG。为了不让它指向常量区,我的字符串都是动态生成的:
		string[] arr = new string[10000];

		foreach(i, ref s; arr) {
			std.gc.fullCollect();
			s = string(toString(i));
		}

		foreach(i, ref s; arr)
			assert(s == toString(i));


不过测试结果让我疑惑不解,它并没有出现任何问题。难道仅仅在struct中保存一个指针就能让它不被GC掉?
qiezi 2007-05-15
如果把测试改为:
		foreach(i, ref s; arr) {
			std.gc.fullCollect();
			char[] cc = toString(i);
			writefln(cc.ptr);
		}

打印出的cc.ptr值都是重复的,可能是2个不同的值,但肯定重复,这表明fullCollect回收后,重新分配的内存就是刚刚释放的地方。
oldrev 2007-05-15
GC会处理依赖的
qiezi 2007-05-15
仅仅一个指针它如何知道有依赖?它如何跟踪这个指针的引用?
oldrev 2007-05-16
GC回收的是垃圾内存,像 ds/ws这样正在使用的是不会回收的,这是GC的基本功能。
oldrev 2007-05-16
我也很不适应GC,感觉和 C++ 完全不同。
tomqyp 2007-05-16
但是C++内存上又很容易出问题,大师们说C++内在应该在哪里分配就在哪里释放,实际应用中很难做到,看到好多比较大的开源项目可能是出于性能考虑,都是用容器来存指针,而不是直接存对象,出现问题很难找出原因.
qiezi 2007-05-16
oldrev 写道
GC回收的是垃圾内存,像 ds/ws这样正在使用的是不会回收的,这是GC的基本功能。

string s = string("abc"w);
这时候已经退出opCall了,ds/ws本身已经没有被使用并且离开了它们的作用域。这时仅有一个原始指针保存它的.ptr,如何能够让它知道正在被使用?
oldrev 2007-05-16
我记得 phobos 里的字符串函数都是实现了 COW 的,你可以看一下 to UTF16 的实现
Global site tag (gtag.js) - Google Analytics