我正在编写一个应用程序,生成一堆 n 个字符串(位)长度 l,然后对所有可能的对进行比较。

我首先为长度为 l 的 n 个字符串分配内存

char* pStr = (char*)(malloc(n * l)); 

然后,我将最后一个字符串的最后一个字符与所有其他字符串的最后一个字符进行比较,并存储结果。此后,从技术上讲,我不再需要存储该字符,因此我可以用来pStr = realloc(pStr, n*l - sizeof(char*))释放该内存。

我想知道这样做是否有意义,比如对每个字符,或者在比较了整个字符串之后对每个字符串都这样做。如果你增加指针的大小,而 realloc 不能连续地这样做,它会将内存复制到一个新位置,这不是很有效。在缩小分配的内存时是否会发生这样的事情,因为它总是可以连续的?

另外,我是否正确地假设使用 realloc 调整大小时释放的内存是指针中的最后一个字符?如果是这样,是否有任何方法可以删除第一个字符并将其余字符移至指针地址?

12

  • 1
    C 和 C++ 是不同的语言,您真正使用的是哪一种?如果是 C++(根据标题)- 请删除 C 标签。


    – 

  • 5
    另外,如果是 C++ – 为什么还要使用mallocfamily ? C++ 有new/ delete,还有更好的 – 容器和智能指针。


    – 

  • “由于内存总是连续的,在缩小分配的内存时是否会发生这种情况?”是的,可能会发生,但并未具体说明。根据经验,对于每次微小的大小变化,使用更少的内存reallocs比使用 s 更好realloc


    – 

  • 1
    相关:;原则上:“如果这样做有意义” – 不,做你提出的任何事情都没有意义,除非你对此有非常有力的论据(但问题中没有提到)。std::string如果需要,可以使用一些容器,如果你只需要字符串的一部分,你可以使用


    – 

  • 1
    据我所知,无法保证realloc使用小于原始大小的调用不会导致分配新块并复制内存。可以想象一个分配器将不同大小的块放置在不同的数据结构中,因此缩小一个块可能会将该块从一个地址移动到另一个地址。


    – 



最佳答案
2

除非您在重新分配之间分配内存,否则不会出现内存耗尽的情况,因此不需要重新分配任何东西。

如果内存不足,那么释放小块内存可能也无济于事。

重新分配到较小尺寸通常会就地发生,尽管对此没有任何保证。(是的,你的假设是正确的,总是块的末尾被切断。)

当您将一个块重新分配为较小的大小时,通常会在底层发生以下情况:标准库首先查看是否可以在新重新分配的块末尾创建一个新的空闲块来保存释放的内存。每个空闲块都以一个标头开头,标头通常包含两个指针(双向链接空闲列表)和一个长度;在 32 位系统上,这是一个完整的 4 + 4 + 4 = 12 个字节,在 64 位系统上则是这个数字的两倍。

如果要释放的字节数小于该值,则标准库无法创建新的空闲块,因此将会发生以下两种情况之一:

  • 重新分配将导致释放零内存,或者
  • 重新分配的块将被移动到其他地方,并产生由此产生的所有开销。

一般来说,动态内存分配(以及重新分配和释放)的开销很大,因此,分配得越少越好。

对于进行大量动态内存分配的 C++ 应用程序,最大的问题之一就是内存碎片,并且内存搅动的次数越多,碎片就越多。

因此,底线是:

对于这种定义模糊的情况,没有明确的答案,但你正在考虑的重新分配不太可能是有效的。事实上,很有可能它们会非常低效

附言

如果您是一名应用程序员,并且您发现自己正在考虑在这里或那里节省字节数量级的内存,或者在这里或那里节省时钟周期数量级的处理时间,那么这些节省根本不值得您付出脑力劳动。

我是否正确地假设使用 realloc 调整大小时释放的内存是指针中的最后一个字符?如果是这样,是否有任何方法可以删除第一个字符并将其余字符移至指针地址?

不,你的假设不正确。

由于分配的内存总是连续的,所以在缩小分配的内存时是否会发生这种情况?

您可以尝试使用此动态分配一个字符数组,然后从前面删除一部分,同时相应地缩小分配的内存大小。