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 的实现
|

