【问题标题】:Is frequent reallocating memory for string a good practice?频繁为字符串重新分配内存是一种好习惯吗?
【发布时间】:2016-12-20 20:02:41
【问题描述】:

我有格式字符串,我正在解析它而不是用输入参数替换格式说明符。现在我考虑在替换参数后如何为这样的结果字符串分配内存。我可以分配这个字符串,只要格式字符串,但不是用其他字符串代替 %s 任何长的都需要在一些不确定的融合中重新分配这个字符串,这使得有必要在代码中进行一些不雅的计算。 所以我想我可以按一个字符一个字符地分配从格式字符串创建的这个字符串,每次都重新分配它:

/*** for loop traversing next chars in format string ***/
// if new char 
str = realloc(str, sizeof(*str) +1); 
// if %s 
str = realloc(str, sizeof(*str) + strlen(in_str)); 
// if %d 
str = realloc(str, sizeof(*str) + strlen(d_str)); 

【问题讨论】:

  • 这些陈述似乎不正确:sizeof(*str) 不是到目前为止分配的字符串的大小。
  • 您可以创建一个轻量级的 String 类(对于 C,一个 struct),它包含一个当前的 max_length(最初应该“对于大多数情况来说已经足够了”)。但是,它会增加大约相同的开销,因为您总是需要检查最大长度之前添加它。
  • 模式str = realloc(str, 不允许从内存不足中恢复
  • 这是一个坏主意(除了已经暗示的错误)。如果您对字符串大小有一个想法(例如“它永远不会超过 160、200、300 个字符”),那么您最好分配一个静态缓冲区,而不是不断地通过内存分配调用来打扰操作系统。根据系统的不同,内存浪费可能比操作系统开销更容易容忍。
  • 您是否遇到了可以通过不重新分配字符串来解决的性能问题?如果是这样,那就不好了,你可以修复它。如果您没有遇到性能问题,请不要担心您调用了多少次realloc()

标签: c string malloc realloc


【解决方案1】:

通常内部库代码处理可变字符串/数组/列表的长度/在 2^n 步骤中执行的任何其他操作 - 即,当您有 4 个字节的内存并需要分配 5 个时,它实际上分配了 8 个。这将将代价高昂的 realloc() 调用次数减少到 ~log(n) 操作。 但是,可能还有其他优化,具体取决于库。

【讨论】:

    【解决方案2】:

    我不会评论其他答案中已充分解决的代码问题。

    为每个单独的字符串扩展行为调用realloc 不一定是一种糟糕的做法。它看起来好像它可能表现不佳,为了解决这个问题,你可以实现一个以更大的增量、更少频率增长字符串的方案。但是,你怎么知道realloc 内部还没有做这种事情呢?例如,您可能认为将 128 字节的字符串增加到 256 字节,然后增加到 512,而不是一次一个字符,这很聪明。但是,如果这些恰好是唯一可用的 malloc 内部块大小,那么 realloc 将不得不逐步通过相同的大小。好的,如何节省realloc 调用的原始数量?但这些只是被更聪明的字符串增长逻辑的调用所取代。

    如果此格式字符串构建循环的性能很重要,请对其进行分析。制作一个减少 realloc 操作的版本并对其进行配置。在您编写的所有目标平台上进行比较,以及性能在哪些平台上很重要。

    如果性能不重要,则针对良好结构、可维护性和代码重用等属性进行优化。构建格式字符串的函数不必了解字符串内存管理。它需要一个抽象接口来处理动态字符串。该接口可以提供一个很好的功能,通过在其尾部添加另一个字符串的副本来就地更改字符串。除了格式字符串生成器之外的函数可以使用这些字符串操作。

    字符串管理代码可以在一个地方决定是否在每次字符串长度发生变化时调用realloc,或者是否将存储大小与长度分开跟踪,从而减少realloc的数量来电。

    【讨论】:

      【解决方案3】:

      这样的代码:

      str = realloc(str, sizeof(*str) +1);
      

      不好。如果realloc 失败,它将返回NULL,但不会返回free(str)。换句话说 - 内存泄漏。您需要将realloc 的结果分配给另一个指针,然后检查NULL 并采取相应措施。

      使用多个realloc 是好是坏取决于你想要获得什么,即性能、可维护性、清晰性等。最好的建议是:按照你喜欢的方式编写代码.然后对其进行剖析。性能问题?不-> 开心。是 -> 重写代码,关注性能。

      【讨论】:

      • ...str = realloc(str, sizeof(*str) +1); 是错误的。只有当代码尝试从失败的分配中恢复时才是错误的。如果对分配失败的响应是对exit()进程的响应,则泄漏无关紧要。
      • @AndrewHenle 除了安德鲁的评论,如果代码因为空指针而崩溃,很可能是这种情况,泄漏也无关紧要。
      • @Kaz - 不能保证。在大多数现代系统上,一切都会好起来的,但作为一段通用的 c 代码,它就很糟糕。见:stackoverflow.com/questions/2213627/…
      • @4386427(在非现代系统上也不能保证取消引用空指针会崩溃)。
      • @Kaz 在malloc() 内存不足后从null 指针取消引用崩溃可能会导致在某些操作系统上创建相当大的核心文件。这可能会产生不利后果。
      猜你喜欢
      • 2017-08-09
      • 1970-01-01
      • 2015-12-14
      • 2020-07-03
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 2011-03-02
      • 2017-10-11
      相关资源
      最近更新 更多