关于右值的范围和内存泄漏
Posted
技术标签:
【中文标题】关于右值的范围和内存泄漏【英文标题】:About rvalues' scope and memory leaks 【发布时间】:2016-04-10 09:35:54 【问题描述】:如果你“永远”留在同一个块中,右值会发生什么?
假设我有以下代码:
char buff[999];
time_t timer;
while(true)
...
time(&timer);
strcpy(buff, ctime(&timer));
...
在每次迭代中,右值 char *
将从 ctime
返回,但它会在迭代结束时被释放还是仅在块完成时被释放?
如果只是在块完成时,那么经过几百万次迭代,内存可能会被完成的右值char*
填满,对吧?
(我用c
和c++
标记了这个,因为我也想知道这两者之间是否有区别)
【问题讨论】:
据我所知,它创建了一个临时对象,其范围取决于终止分号,即从 ctime(&timer) 返回的内容的范围在该语句的分号(;) 处,除非什么它返回是在堆上创建的,在这种情况下你有责任释放它。 阅读ctime
的手册页:四个函数 asctime()、ctime()、gmtime() 和 localtime() 返回指向静态数据的指针,因此不是线程安全的。
你不会永远停留在同一个块中,每次迭代都会创建一个新块。但这与你的问题无关。
为什么线程安全与内存泄漏有关? @DieterLücking
@kuhaku 我只是在复制整行。
【参考方案1】:
由于历史原因,C 库中的函数返回不同类别的内存:
不需要释放的静态分配内存。该库通常在其代码中将其声明为静态数组,并将在每个函数调用中重用相同的内存区域。ctime
和localtime
就是这方面的例子。请勿不释放此内存。 (可能值得一提的是,这些函数被认为已被弃用,并且由于它们不适合多线程操作而逐渐消亡)
动态分配的内存需要由调用者释放。该内存由库函数动态分配,该库函数使用malloc()
分配该内存,将指针返回给您,并希望您在完成后将其分配给free()
。 strdup()
就是这个表单的一个很好的例子。
您只需需要知道您正在使用的特定库调用将返回哪个类,以便知道您是否应该free()
那个内存。请查阅相应调用的手册页。
在ctime()
的情况下,循环中的迭代绝对无关紧要。由于库在每次迭代中返回完全相同的缓冲区地址,该地址被写入堆栈帧中的完全相同的位置,因此不存在内存泄漏之类的情况。如果您在循环中改为调用strdup()
,则会造成内存泄漏。
【讨论】:
我认为他是在询问ctime
返回的指针(不是该指针指向的空间)
返回的指针只是一个指针,还有一个auto
变量,在循环的每次迭代中占用相同的空间——它会有什么问题?【参考方案2】:
ctime
返回的指针在 C 和 C++ 中都称为 值。它不是一个对象,因此它没有生命周期或存储持续时间。
您的问题就像是在问:在代码for(;;) 10 + 10;
中,内存会被20
填满吗? (答案是:否)。
(不要与 C++ 中的 temporaries 混淆,它们是对象并且确实有生命周期)。
在 C 中,可以访问函数的返回值,直到当前语句结束(即在您的情况下为下一个 ;
),尽管对于标量类型,这无关紧要,因为没有语法会表达这样的访问。这个规定是指类似于printf("%d\n", foo().x);
的东西,其中foo()
按值返回一个结构。
代码 printf("%d %d %d %d %d %d %d %d %d %d\n, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x, foo().x);
确实需要编译器实现 10 个返回值对象,但它们都死在 ;
处。
注意。您的问题包含固有的误解。当到达 时,该块结束,即使还有另一个迭代。下一次迭代是一个新的块,在块内声明的变量在概念上被销毁并在每次迭代时重新创建。
【讨论】:
【参考方案3】:(我这里说的是 C,对于 C++,这要复杂得多)
局部变量,例如你的
char buff[999];
time_t timer;
...通常在输入函数时一起分配。此类变量要么在堆栈帧中分配空间(在 buff 的情况下),要么直接在硬件寄存器上(可能在定时器的情况下)。
所有这些分配都是在一条机器指令中一起完成的,只需将指针移动到堆栈顶部即可。每个函数调用只有一个局部变量的实例,因此不会因为循环使用它们而导致内存填满。此外,该内存区域可以增长的大小(大约 10 兆字节)会有一个相对较低的全局限制。
所有局部变量在函数退出时通过销毁堆栈帧自动释放。同样,这只是通过再次将堆栈指针移回来完成。这与静态函数变量(只是可访问性有限的全局变量)和必须显式分配或释放的动态分配(堆)变量形成对比。
堆栈框架有点过于复杂,无法在此处完整介绍,但我建议您阅读它们,因为了解函数调用的工作原理确实有助于对 C 编程的一般理解。
如果您对变量存储有任何更具体的问题,我相信您可以在此处找到有关堆栈溢出的帮助,因为我们大多数 C 程序员都喜欢谈论这类事情 :)
【讨论】:
这里没有解决问题,是关于ctime
的返回值
@M.M 我认为 ctime() 主要用作示例,并且问题具有更一般的性质。但也许我误解了。
我一般地询问了右值,ctime
只是一个例子。 @MM
您的回答似乎只谈论局部变量或静态变量,很难看出“右值”是如何指代的
右值存在于标准中,而不是现实中。我读到的 OP 的问题实际上是关于局部变量如何工作、如何分配和处置的。关于 OP,他是否完全理解“右值”的含义并在正确的正式上下文中使用它并不明显。我认为他的意思可能只是一般意义上的“价值”。以上是关于关于右值的范围和内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章