C 垃圾收集器会在这里做什么?

C 垃圾收集器会在这里做什么?,c,memory-management,garbage-collection,C,Memory Management,Garbage Collection,我在另一个线程中看到了这段代码 void foo { int *n = malloc(sizeof(int)); *n = 10; n++; printf("%d", *n); } 这里的错误是显而易见的n未被取消引用。 内存泄漏。 让我们假设有一个垃圾收集器在这里工作。对初始值n的引用计数现在为零,因为n不再引用它。所以它是垃圾,然后又回来了。但是n所指的新位置呢?从技术上讲,这个内存区域还没有分配。那么这里的引用计数会增加吗?我改变了主意;我想是的。问题是这样的代码:

我在另一个线程中看到了这段代码

void foo {
  int *n = malloc(sizeof(int)); 
  *n = 10; 
  n++;
  printf("%d", *n);
}
这里的错误是显而易见的<代码>n未被取消引用。 内存泄漏。
让我们假设有一个垃圾收集器在这里工作。对初始值
n
的引用计数现在为零,因为
n
不再引用它。所以它是垃圾,然后又回来了。但是
n
所指的新位置呢?从技术上讲,这个内存区域还没有分配。那么这里的引用计数会增加吗?

我改变了主意;我想是的。问题是这样的代码:

int* n = malloc(sizeof(int));
n++;
int* o = n;
int* p = n;
n = malloc(sizeof(int));

现在有三个对
n
指向的内存的引用,但垃圾收集器只看到一个。执行
n=NULL将导致清除,尽管存在
o
p
指针。像这样的指针灵活性是C垃圾收集器如此困难的主要原因;我不确定在C语言中是否可能有一个完美的垃圾收集器,因为您可以有一些指针,这些指针的地址在运行时之前是未知的。

正确实现的垃圾收集器将按如下方式工作:

int *pi = malloc(sizeof int);
*pi = 10;
这里一切都很好

pi++;
此语句允许
pi
指向分配的int后面,这是ISO C99标准明确允许的(参见6.5.6p7、6.5.6p8)。代码后面可能有
pi--
,因此分配的int仍然可以访问。或者可以通过表达式
pi[-1]
来访问它,这一点非常有效

pi = NULL;
此时,无法再访问分配的int,因此垃圾收集器可能会收集内存


综上所述:指向对象的开始、指向该对象中间的某处或指向该对象后面的位置的所有指针都可以用来访问对象。因此,如果内存中存在这样的值,则不能对对象进行垃圾收集。

C垃圾收集器不执行引用计数。它们通常是标记扫描,在块上操作,而不是在单个字节上操作。在您的示例中,gc将标记块,而不是地址。即便如此,你问题的核心仍然是正确的:

标记阶段到达“坏”指针时会做什么?

一个保守的收藏家完全忽略了这一点。初始malloc中的内存将被收集。

您是在考虑我正在考虑的同一个想象中的垃圾检测器吗?为什么另一个人删除了他的答案?程序不太可能在printf之后继续运行,因为您取消了对无效指针的引用,GC或no-GC.@kaizer.se:内存是以块的形式分配的,并且该块可能大于实际请求的内存量。因此,这个程序可能运行得很好——这取决于编译器。如果你实现一个GC,你仍然可以这样做,但是6.5.6p8只是说,在分配内存+2之前,操作p+k不能溢出,所以你总是有p+last_elpi+1
)后面的位置可能无效,因此指向该位置的指针将不会被认为与
pi
…6.5.6p8精确地指出pi+1无效:”结果指向数组对象的最后一个元素后一个元素,它不应用作计算的一元*运算符的操作数“对我来说,这一段的要点是加法pi+1不能溢出,以使pipi+1有效(在递增之前),但
*(pi+1)
无效。这正是6.5.6p8所说的。该段说明表达式
pi+1
仍然表示与分配的int相关的指针。