C 隐式解除分配

C 隐式解除分配,c,C,在程序中,如果声明了一个变量,它将分配空间,在动态内存分配的情况下,在程序结束时将释放空间。我知道它在堆中分配空间,但我的问题是:为什么编译器不能隐式释放堆中的内存?这意味着编译器必须改变程序的语义,这超出了编译器首先应该做的事情 由于性能或其他原因,您可能不希望释放堆内存 正如一些人在回答中提到的那样,垃圾收集依赖于运行时系统跟踪内存区域及其引用,但C中不存在这样的运行时 为什么编译器不能隐式释放堆中的内存 因为它不知道/不知道是否还有其他东西需要访问堆节点 你在这里说的是垃圾收集。C的类型系

在程序中,如果声明了一个变量,它将分配空间,在动态内存分配的情况下,在程序结束时将释放空间。我知道它在堆中分配空间,但我的问题是:为什么编译器不能隐式释放堆中的内存?

这意味着编译器必须改变程序的语义,这超出了编译器首先应该做的事情

由于性能或其他原因,您可能不希望释放堆内存

正如一些人在回答中提到的那样,垃圾收集依赖于运行时系统跟踪内存区域及其引用,但C中不存在这样的运行时

为什么编译器不能隐式释放堆中的内存

因为它不知道/不知道是否还有其他东西需要访问堆节点

你在这里说的是垃圾收集。C的类型系统不够强大,无法实现(非保守)垃圾收集


请注意,即使在垃圾收集语言中,也很少由编译器决定是否/何时取消分配动态分配的堆节点。

编译器不能这样做,因为这是运行时的决定。如果不执行程序,您无法知道何时取消分配

这是在垃圾收集系统中完成的

那么这段代码呢:

int* p[1000000];
for (i= 0; i < 1000000; i++)
{
   p[i]= malloc(1000000);

   // Initialize this block
}

for (i= 0; i < 1000000; i++)
{
   if (Condition(i))
   {
     // Process this block
   }
}
int*p[1000000];
对于(i=0;i<1000000;i++)
{
p[i]=malloc(1000000);
//初始化此块
}
对于(i=0;i<1000000;i++)
{
如果(条件(i))
{
//处理此块
}
}
您谈论的是动态内存分配,这意味着使用
malloc()和朋友创建对象。在这种情况下,许多实现使用操作系统提供的“堆”之类的东西。这样的操作系统通常在退出时执行必要的清理

但是请注意,C对此一无所知。C只指定有一个称为已分配对象的对象,它具有动态存储持续时间,这意味着它一直保持活动状态,直到调用
free()
。由于C语言的设计方式使得它几乎可以在任何地方实现,所以它甚至不需要操作系统。因此,虽然省略
free()
在典型的PC等设备上有效,但该代码可能会在某些平台上导致问题,而在这些平台上,没有任何东西可以“在您之后清理”。您甚至可以在长时间运行的程序中遇到问题,因为当您从未调用
free()
时,分配的对象可能会不断累积,这称为内存泄漏

也就是说,C包含了一个简单的隐式释放概念:具有自动存储持续时间的对象。一旦执行离开其封闭范围,它们就会被释放。默认情况下,在函数中声明的任何变量都具有自动存储持续时间


还请注意,许多较新的语言不需要显式管理动态分配对象的内存。这仅仅是因为它们附带了一些包含垃圾收集器的运行时代码。因此,用这些语言编写的程序需要额外的代码,例如链接到它的代码(或者是执行代码的虚拟机的一部分,比如Java)。C不包括这样的东西,但是有一些垃圾收集器可供C使用,您可以显式使用。如果您对此感兴趣,可以看一看。

编译器只是将您的C代码翻译成机器代码。它不“知道”在程序代码中访问分配的内存块的时间,因为它不运行代码。为了允许自动释放,需要一个特殊的运行时工具来跟踪对堆上对象的引用,比如C#和JavaScript等语言中使用的垃圾收集器。然而,这些垃圾收集器通常不会立即释放内存,而是等到内存不足时再释放。然后,他们将处理迄今为止检测到的所有未使用的“垃圾”内存。

需要明确指出的是,编译器有可能决定是否释放给定适当类型系统的对象,尽管这是否算作GC在很大程度上取决于您的定义(通常被宣传为“无需GC!”)。正如您所说,C没有这样的类型系统。这类语言(如Rust)对您可以使用它们做的事情有限制,并且/或者对内存管理生命周期有不同的思考方式。例如,在Rust中,应用程序需要显式地打破循环数据结构中的循环,以使其被回收。(当涉及到图表中的循环时,没有免费的午餐!)最好在标记为C的问题中使用C示例。不幸的是,
new
在C语言中不存在。这值得否决吗?语言实际上是不相关的。@YvesDaoust虽然不是我的DV,但我仍然认为是的,是的。如果语言不相关,你也可以用一点Java来回答:o@YvesDaoust当然会的,你不能指望有人问C时知道
new
应该是什么意思!顺便说一句,我不明白你想用这个代码片段表达什么。。。想解释一下吗?很不清楚你在问什么。一般来说:也许你分配内存是有原因的。编译器无法决定您是否忘记取消分配,或者您是否出于某种原因将其留在那里。编译器不会分配或取消分配任何内存。它只把源代码翻译成机器代码。编译器甚至对用于分配和取消分配内存的函数一无所知。@PeterJ_01这不一定是真的,许多编译器确实知道标准函数的语义,并使用它应用附加检查、优化代码等等。但是你可以说编译器不需要了解任何函数。@PeterJ_01我不需要