【问题标题】:Does memory allocated in a function still stay allocated after the function returns?函数返回后,函数中分配的内存是否仍保持分配状态?
【发布时间】:2014-10-23 10:45:11
【问题描述】:

对于下面的代码: (1) “main”调用函数“f1”。 (2) 函数“f1”进行一些数字运算;使用 malloc 创建一个“char”数组,然后将该数组的指针返回给主数组(不取消分配-释放-数组)。

我有 3 个与此案相关的问题: (1) 我假设,虽然函数“f1”已经终止,但分配的 char 数组仍然保持分配状态,直到主程序完全终止。也就是说,分配的内存仍然属于 main 并且没有其他进程可以从外部访问(我的意思是,干扰)它。我对吗? (2) 是否必须在程序终止之前释放数组(在“f1”中分配)(或者是否在主程序终止后立即释放)? (3) 如果第二个问题的答案是“是”,那么如何释放分配在另一个函数中的数组?

注意:我希望停留在纯 c 的范围内,而不是溢出到 c++。

char *f1 (...) {
    ...
    ...
    char *fTmp = malloc (length1 * sizeof (char));
    char *fData = malloc (length2 * sizeof (char));
    ...
    ...
    free (fTmp);
    return (fData);
}

int main () {
    char *fData = f1 (...);
    ...
    return (0);
}

【问题讨论】:

    标签: c arrays function malloc


    【解决方案1】:

    我假设,虽然函数“f1”已经终止,但分配的 char 数组仍然保持分配状态,直到主程序完全终止。

    没错。动态分配的内存与函数无关,属于进程。

    也就是说,分配的内存仍然属于main,没有其他进程可以从外部访问它。我说的对吗?

    内存不属于main()(作为函数),而是属于自己的处理(其中main()只是入口点)。在具有内存保护的系统中(每个进程都与其他进程隔离),它无法从外部访问。但是,您可以以系统特定的方式分配它以跨进程共享内存。

    我是否必须在程序终止之前释放数组(在“f1”中分配)(或者它是否在主程序终止后立即释放)?

    是的。未分配的内存 - 在大多数系统中 - 在进程终止时由操作系统自动释放,但这取决于系统。 IMO 即使操作系统这样做,您也应该始终解除分配,使用这种自动解除分配作为红旗(我忘记解除分配,这是一个错误吗?我错过了什么?)。此外,如果 f1 被调用 1000 次,它每次都会泄漏内存,很快就会耗尽所有可用内存。想想服务器中的一个进程,它可能(并且应该)运行多年。

    如果第二个问题的答案是“是”,那么如何释放在另一个函数中分配的数组?

    当谁分配内存也释放它时,这很好。如果不可能,那么调用者将对此类内存负责。例如,strdup() 所做的事情。在这种情况下,被调用的函数必须(以某种方式)返回指向已分配内存的指针(或可由另一个专用函数使用的句柄/令牌)。例如:

    char* pBuffer = f1();
    // Use it
    free(pBuffer);
    

    注意,如果你想隐藏这样的internal指针,有很多技巧。您可以使用令牌(例如整数、字典中的键)、typedef 或不透明类型。

    【讨论】:

    • 我也在做同样的事情;也就是说,我使用传递的指针释放了另一个进程中创建的数组。我不确定我一直在做的事情是正确的。因此,您的方法似乎是最接近的答案:“分配内存的人也释放它很好。如果不可能,那么调用者将负责此类内存。”
    • @merkez3110 但您不能在进程之间共享指针(除非您在没有受保护的虚拟内存的环境中运行)。
    • 请原谅我使用了错误的术语:“过程”。在我上面的评论中,我的意思是同一个程序中的不同“功能”,而不是不同的进程。谢谢大家。
    【解决方案2】:

    如果你不释放你不使用的内存,最终这会累积 - 如果你用许多其他指针这样做 - 你的程序可能会耗尽内存。在使用 free 函数释放内存块后,我还建议将 NULL 分配给指针,因为这可以防止悬空指针,即使您已释放指针,如果您尝试访问它,您可能会得到 undefined行为,而对 NULL 指针的访问和操作会导致崩溃,因此您可以轻松追踪问题

    【讨论】:

      【解决方案3】:

      malloc 在堆上分配内存,因此该内存保持分配状态,直到被free 函数或程序成功终止释放。
      在您的情况下,您在f1 中释放了ftemp,因此在函数终止后它不再存在。 fdata 仍在堆上,main 可以访问它,因为您正在返回指向该分配位置的指针。

      一旦main 成功终止,fdata 指向的内存就会被释放。

      因此,一旦您不再需要它就释放内存被认为是好的。在程序结束时释放块是没有意义的,因为当进程终止时,程序的所有空间都会归还给系统(考虑到现代操作系统)。

      【讨论】:

        【解决方案4】:

        您可以在 C 中使用两种基本类型的内存。这两种类型是堆栈和堆。通常,您在函数中创建的变量将在堆栈上分配,并在函数返回时被释放。在堆中分配的内存将持续存在,您有义务在程序中管理该分配。堆中的内存将保持分配状态,直到您使用指向数据块的指针(内存地址)释放为止。

        对这两个方面进行一些阅读将有助于您理解。我要指出的是,您有两个 fData 实例,每个实例都有自己的范围。两个指针都指向你分配的内存:

        char *fData = malloc (length2 * sizeof (char));
        

        .. 即使它们在您的代码执行时传入和传出范围。

        【讨论】:

          【解决方案5】:

          使用malloc 将在堆上分配内存,直到你free 它。

          这意味着您需要确保每个 malloc 都有相应的 free,也不意味着没有其他进程无法访问您的数据。它只是一个地址的值。

          在您的 main 中,您必须 free(fData) 以避免内存泄漏。

          总结一下:

          1) 你的第一个假设是正确的,第二个和第三个不是。它将保持分配状态,但它不是 main 本地的,并且在终止时不会绑定到进程

          2) 是的,你必须释放它

          3) 使用从函数中获得的指针。如果您没有从函数返回指向已分配数据的指针,请确保该函数 frees 它。

          【讨论】:

            【解决方案6】:
            1. 是的,使用malloc() 分配的内存会一直保留,直到它被释放。一个函数怎么可能将可变大小的数据返回给它的调用者?

            2. 当程序退出时,它分配给malloc() 的所有内存都被释放。但是,在程序终止之前保留大量不需要的内存通常不是一个好主意,因为它会影响性能,或者系统可能会耗尽虚拟内存。对于长时间运行的程序来说,这可能是一个特别值得关注的问题,它们的内存使用有时会不断增长,直到它们用完所有可用的虚拟内存。

            3. 您在函数返回的指针上调用free()。因此,在您的情况下,main() 可以在使用数组完成后执行 free(fData)

            任何 C 编程课程或教科书都应涵盖这些内容。

            【讨论】:

              【解决方案7】:
              1. 是的,它仍在堆中。但是,您对过程的概念感到困惑。除非您创建另一个进程(在 *nix 上使用 fork),否则它仍然是同一个进程。

              2. 在不使用内存时释放内存是一个好习惯。但是如果程序正常终止,分配的内存会被系统释放。

              3. 像这样:

                int main () {
                    char *fData = f1 (...);
                    //...
                    free(fData);
                    //...
                }
                

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-12-17
                • 2021-10-14
                • 1970-01-01
                • 1970-01-01
                • 2010-09-30
                • 2013-12-17
                • 2013-10-31
                • 2013-11-10
                相关资源
                最近更新 更多