关于右值的范围和内存泄漏

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*填满,对吧?

(我用cc++标记了这个,因为我也想知道这两者之间是否有区别)

【问题讨论】:

据我所知,它创建了一个临时对象,其范围取决于终止分号,即从 ctime(&timer) 返回的内容的范围在该语句的分号(;) 处,除非什么它返回是在堆上创建的,在这种情况下你有责任释放它。 阅读ctime 的手册页:四个函数 asctime()、ctime()、gmtime() 和 localtime() 返回指向静态数据的指针,因此不是线程安全的。 你不会永远停留在同一个块中,每次迭代都会创建一个新块。但这与你的问题无关。 为什么线程安全与内存泄漏有关? @DieterLücking @kuhaku 我只是在复制整行。 【参考方案1】:

由于历史原因,C 库中的函数返回不同类别的内存:

不需要释放的静态分配内存。该库通常在其代码中将其声明为静态数组,并将在每个函数调用中重用相同的内存区域。 ctimelocaltime就是这方面的例子。请勿释放此内存。 (可能值得一提的是,这些函数被认为已被弃用,并且由于它们不适合多线程操作而逐渐消亡) 动态分配的内存需要由调用者释放。该内存由库函数动态分配,该库函数使用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,他是否完全理解“右值”的含义并在正确的正式上下文中使用它并不明显。我认为他的意思可能只是一般意义上的“价值”。

以上是关于关于右值的范围和内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

程序结束后内存泄漏有影响吗?

java 关于内存泄漏和内存溢出

关于IOS内存泄漏

NSMutableArray 和属性泄漏内存

内存泄漏和内存溢出的优化

内存泄漏和内存溢出的优化