繁体   English   中英

多次运行程序时如何使用或释放​​动态分配的内存?

[英]How to use or free dynamically allocated memory when I run the program multiple times?

如何释放动态分配的内存?

假设输入(假设它是由用户给定的)是1000,现在如果我分配了1000的内存,并且在此之后(第二次)如果用户给出的输入是500,我可以重用已经分配的内存吗?

如果用户现在输入值说3000,我该如何处理? 我可以重用已经分配的1000个内存块,然后再创建2000个内存块吗? 还是应该创建所有3000个内存块?

哪些是明智的?

#include <stdio.h>
#include <stdlib.h>
typedef struct a
{
  int a;
  int b;
}aa;

aa* ptr=NULL;
int main() {
//code
int input=2;
ptr=malloc(sizeof(aa)*input);

for(int i=0;i<input;i++)
{
    ptr[i].a=10;
    ptr[i].b=20;
}

for(int i=0;i<input;i++)
{
    printf("%d  %d\n",ptr[i].a,ptr[i].b);
}

return 0;
}

我相信,您需要阅读有关分配内存的“生命周期”

对于诸如malloc()和family之类的分配器函数malloc()对于“内存管理函数”,从C11第7.27.2章引用)

[...]分配对象的生存期从分配一直到释放为止。 [....]

因此,分配后,指向内存的返回指针将保持有效,直到被释放。 有两种方法可以释放它

  • 在程序内部使用对free()的调用
  • 一旦程序终止。

因此,从分配点到程序终止或free()调用(以较早者为准free() ,分配的内存都是可用的。


就目前而言,我要澄清两个方面。

  • 方案1:

     You allocate memory (size M) You use the memory You want the allocated memory to be re-sized (expanded/ shrinked) You use some more You're done using 

    如果这是您期望的流程,则可以使用realloc()调整分配的内存大小。 完成后,使用free()

  • 方案2:

     You allocate memory (size M) You use the memory You're done using 

    如果是这种情况,请在完成后使用free()

注意:在这两种情况下,如果程序多次运行,则在每个单独的调用中发生的分配之间或之间没有连接。 他们是独立的。

当您使用动态分配的内存并调整其大小时,重要的是要准确跟踪已为其分配了多少个元素。

我个人喜欢将使用中的元素数保留在名为used变量中,而我为size分配的内存数也要保留。 例如,我可能会创建一个用于描述一维双精度数组的结构:

typedef struct {
    size_t  size; /* Number of doubles allocated for */
    size_t  used; /* Number of doubles in use */
    double *data; /* Dynamically allocated array */
} double_array;
#define DOUBLE_ARRAY_INIT { 0, 0, NULL }

我想将动态分配的内存指针显式初始化为NULL ,并将它们各自的大小初始化为零,因此我只需要使用realloc() 这行得通,因为realloc(NULL, size)完全等同于malloc(NULL) 我还经常利用以下事实: free(NULL)是安全的,什么也不做。

我可能会写几个辅助函数。 也许可以确保数组中at_least条目有空间的函数:

void double_array_resize(double_array *ref, size_t at_least)
{
    if (ref->size < at_least) {
        void *temp;

        temp = realloc(ref->data, at_least * sizeof ref->data[0]);
        if (!temp) {
             fprintf(stderr, "double_array_resize(): Out of memory (%zu doubles).\n", at_least);
             exit(EXIT_FAILURE);
        }

        ref->data = temp;
        ref->size = at_least;
    }

    /* We could also shrink the array if
       at_least < ref->size, but usually
       this is not needed/useful/desirable. */
}

我肯定会编写一个帮助程序函数,该函数不仅释放所使用的内存,而且还更新字段以反映该情况,以便在释放之后调用double_array_resize()是完全安全的:

void double_array_free(double_array *ref)
{
    if (ref) {
        free(ref->data);
        ref->size = 0;
        ref->used = 0;
        ref->data = NULL;
    }
}

程序可能会使用上面的方法。

int main(void)
{
    double_array  stuff = DOUBLE_ARRAY_INIT;

    /* ... Code and variables omitted ... */

    if (some_condition) {
        double_array_resize(&stuff, 321);

        /* stuff.data[0] through stuff.data[320]
           are now accessible (dynamically allocated) */
    }

    /* ... Code and variables omitted ... */

    if (weird_condition) {
        /* For some reason, we want to discard the
           possibly dynamically allocated buffer */
        double_array_free(&stuff);
    }

    /* ... Code and variables omitted ... */

    if (other_condition) {
        double_array_resize(&stuff, 48361242);

        /* stuff.data[0] through stuff.data[48361241]
           are now accessible. */
    }

    double_array_free(&stuff);

    return EXIT_SUCCESS;
}

如果我想将double_array用作堆栈,则可以这样做

void double_array_clear(double_array *ref)
{
    if (ref)
        ref->used = 0;
}

void double_array_push(double_array *ref, const double val)
{
    if (ref->used >= ref->size) {
        /* Allocate, say, room for 100 more! */
        double_array_resize(ref, ref->used + 100);
    }

    ref->data[ref->used++] = val;
}

double double_array_pop(double_array *ref, const double errorval)
{
    if (ref->used > 0)
        return ref->data[--ref->used];
    else
        return errorval; /* Stack was empty! */
}

每当数组空间不足时,上面的double_array_push()再分配100个双打。 但是,如果您推动了数百万的双打,这将意味着数以万计的realloc()调用,这通常被认为是浪费的。 取而代之的是,我们通常采用重新分配策略 ,该策略将大小与现有大小成比例地增长。

我的首选策略是类似(伪代码)的东西

If (elements in use) < LIMIT_1 Then
    Resize to LIMIT_1
Else If (elements in use) < LIMIT_2 Then
    Resize to (elements in use) * FACTOR
Else
    Resize to (elements in use) + LIMIT_2
End If

LIMIT_1通常是一个很小的数字,是分配的最小大小。 LIMIT_2通常是一个很大的数字, LIMIT_2为2 20 (两百万加零钱),因此最多可以分配LIMIT_2未使用的元素。 FACTOR介于1和2之间; 许多建议2 ,但我更喜欢3/2

该策略的目标是将realloc()调用的数量保持在可接受(不引起注意)的水平,同时使分配但未使用的内存量保持较低。

最后要注意的是,如果您出于相同(或非常相似)的目的重用它,则应仅尝试保留动态分配的缓冲区。 如果您需要不同类型的数组,并且不需要较早的数组,则只需free()较早的数组,然后malloc()新建一个数组(或让助手中的realloc()做到这一点)。 无论如何,C库将尝试重用相同的内存。

在当前的台式机上,与该程序的启动时间相比,大约一百或一千个malloc()realloc()调用可能不太明显。 因此,最小化这些呼叫的数量并不是很重要。 您要做的是使代码易于维护和调整,因此逻辑重用以及变量和类型名称很重要。

重用缓冲区的最典型情况是逐行读取文本输入。 我使用POSIX.1 getline()函数来这样做:

char   *line = NULL;
size_t  size = 0;
ssize_t len;  /* Not 'used' in this particular case! :) */

while (1) {
    len = getline(&line, &size, stdin);
    if (len < 1)
        break;

    /* Have 'len' chars in 'line'; may contain '\0'! */
}
if (ferror(stdin)) {
    fprintf(stderr, "Error reading standard input!\n");
    exit(EXIT_FAILURE);
}

/* Since the line buffer is no longer needed, free it. */
free(line);
line = NULL;
size = 0;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM