【问题标题】:Can memory leak occur for memory allocated through static variable?通过静态变量分配的内存会发生内存泄漏吗?
【发布时间】:2021-09-22 20:20:49
【问题描述】:

给了我一组源代码,我的情况如下:

假设我有一个源文件 (source1.c),其中包含:

static float *var;

void alloc_mem ()
{
  var = (float *) malloc(N * sizeof(float));
}

void some_function (float *data)
{
  // do something with var and data
}

在主函数中,我有

int main()
{
  alloc_mem ();
  some_function (data);
}

现在,我无法通过在 main 中调用 free(var) 来释放分配给 var 的内存,因为它不在此范围内。

这种情况会导致内存泄漏吗?如果我在 source1.c 中定义一个函数为

void dealloc_mem()
{
  free(var);
}

在 main 的末尾调用它,它会工作吗?

【问题讨论】:

  • 会发生内存泄漏吗?是的,如果你调用 alloc_mem() 两次,而没有对内存的干预调用 free(),无论指针变量的位置和位置如何。
  • 是的,您仍然可能有内存泄漏。通常,C 不知道定义了哪些指针或它们如何获取值,无论它们是否为static。所以你需要自己释放内存(或者等到程序存在,在这种情况下所有东西都被释放(但不是通过调用free))。
  • 请注意,如果alloc_mem() 被多次调用,则肯定存在内存泄漏。仅调用一次时,您最终会得到“退出时正在使用的内存”或“仍可访问”的内存,这并不总是被视为内存泄漏。添加释放器意味着您可以更轻松地发现其他泄漏——少了一件需要担心的事情。此外,您可以使用atexit() 注册dealloc_mem(),以便在程序退出时调用它(如果您可以使用at_quick_exit(),则可以使用at_quick_exit() — 在C11 中添加)。

标签: c memory-leaks static malloc free


【解决方案1】:

是的,从技术上讲确实是内存泄漏。

实际上,这通常是可以接受的,因为唯一可以安全释放内存的时间是在程序退出期间,此时,是否释放内存并不重要 - 它仍然会程序终止后返回操作系统。

为了迂腐,你可以free main 末尾的内存,但是有更多的方法可以终止程序,而不仅仅是从 main 返回,所以正确的方法是注册退出处理程序。但这可能有点矫枉过正。

我不得不提一下,从提供的代码中绝对不清楚为什么首先需要动态分配,所以我没有解决这部分。

【讨论】:

  • 正确的方法是注册退出处理程序 请注意,即使这样,也有一些方法可以在不调用任何退出处理程序的情况下退出进程,例如调用_Exit()
  • @AndrewHenle 当然,但我们对此无能为力(例如,还有人给机架断电),所以我们只能接受这个现实。
【解决方案2】:

通过静态变量分配的内存会发生内存泄漏吗?

当然可以,如果您重新分配var


现在,我无法通过在 main 中调用 free(var) 来释放分配给 var 的内存,因为它不在该范围内。

您可以通过返回 var 轻松解决这个问题。


如果我将source1.c 中的函数定义为

void dealloc_mem()
{
    free(var);
}

在 main 的末尾调用它,它会工作吗?

是的,当您不再需要分配的内存时,适当地调用dealloc_mem 会正常工作。


内存分配的通用规则是每个*alloc 都应该有一个free

总是释放内存是一个好习惯,即使在执行结束时,当然当程序结束时,系统会释放内存,但是如果你通过内存检查器运行它还是会抱怨。


除此之外,我看不到您需要这种构造的情况,也许您可​​以解释一下为什么您的代码具有这样的结构,否则我们可能会遇到XY problem

【讨论】:

  • 动态分配,因为静态分配被认为太大了?如果替代方案是堆栈分配,这将很重要——目前尚不清楚这就是这里的问题。目前,这是一个 XY 问题。
【解决方案3】:

是的,这确实会导致内存泄漏。为了说服自己,您可以使用valgrind 进行检查。将以下内容放入您的source.c

#include <stdlib.h>

static float *var;

void alloc_mem ()
{
    int N = 100;
    var = (float *) malloc(N * sizeof(float));
}

void dealloc_mem()
{
    free(var);
}

void some_function (float *data)
{
  // do something with var and data
}

int main()
{
    float *data;

    alloc_mem ();
    some_function (data);
}

现在运行gcc -o executable source.c,然后运行valgrind --leak-check=yes ./executable。这将表明您确实丢失了 400 个字节(在此示例中,100 个浮点数中的每个浮点数为 4 个字节)。如果您按照main 末尾的建议致电dealloc_mem();,则不会有任何泄漏。

【讨论】:

    猜你喜欢
    • 2013-11-06
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    • 2016-11-03
    • 1970-01-01
    • 2016-12-11
    • 2023-03-28
    • 1970-01-01
    相关资源
    最近更新 更多