0

对于一个小型的嵌入式应用程序,我编写了一些函数 + 结构作为字符串缓冲区(类似于 C++ 中的 std::stringstream)。

虽然这样的代码工作正常,但有一些不那么小问题:

  • 我以前从未在 C 中编写过手动分配使用不断增长的内存的函数,因此恐怕仍有一些怪癖需要解决
  • 看起来代码分配的内存比它实际需要的多得多,这是非常糟糕的
  • 由于 valgrind 报告的警告,我已经从代码中的一个地方切换malloccalloc了,这成功地删除了警告,但我不完全确定我是否真的正确使用它

我的意思是它分配的比它真正需要的多的例子(使用 56k 文件):

==23668== HEAP SUMMARY:
==23668==     in use at exit: 0 bytes in 0 blocks
==23668==   total heap usage: 49,998 allocs, 49,998 frees, 1,249,875,362 bytes allocated

......它看起来不正确......

有问题的代码在这里(太大而无法<code>在 SO 的字段中复制):http ://codepad.org/LQzphUzd

需要帮助,我很感激任何建议!

4

4 回答 4

2

您增加缓冲区的方式相当低效。对于每一小段字符串,你 realloc() 内存,这可能意味着分配了新内存并复制了“旧”内存的内容。这很慢,并且会使您的堆碎片化。

更好的是以固定数量或固定百分比增长,即使新尺寸为旧尺寸的 1.5 或 2 倍。这也浪费了一些内存,但会使堆更可用,并且不会制作那么多副本。

这意味着您必须跟踪两个值:容量(分配的字节数)和长度(字符串的实际长度)。但这不应该太难。

我将介绍一个函数“FstrBuf_Grow”来处理所有这些。您只需使用要添加的内存量来调用它,并且FstrBuf_Grow会在必要时通过重新分配来确保容量与要求相匹配,至少在必要时重新分配。

...

void FstrBuf_Grow(FstringBuf *buf, size_t more)
{
    while (buf->length + more) > buf->capacity
        buf->capacity = 3 * buf->capacity / 2;
    buf->data = realloc(buf->data, buf->capacity + 1);
}            

乘以capacity1.5 直到data足够大。您可以根据需要选择不同的策略。

于 2011-09-02T06:55:38.810 回答
1

,strncat(ptr->data, str, len);前移ptr->length = ((ptr->length) + len);并使用strncpy(ptr->data+ptr->length.... 而ptr = NULL;inDestroy是没用的。

“库”的代码似乎是正确的,但请注意您正在不断地重新分配缓冲区。通常你应该尽量少增加缓冲区(例如每次你需要增加缓冲区时,你使用 max(2* 当前大小,4) 作为新大小),因为增加缓冲区是 O(n)。大内存分配可能是因为你第一次分配一个小缓冲区。然后你将它重新分配到一个更大的缓冲区中。然后你需要将它重新分配到一个更大的缓冲区中,这样堆就会增长。

于 2011-09-02T06:47:01.310 回答
0

看起来您正在为每个追加重新分配缓冲区。难道你不应该只在你想追加超过它可以容纳的东西时才增长它吗?

重新分配时,您希望使用一种策略来增加缓冲区的大小,该策略可以在分配数量和分配的内存量之间进行最佳权衡。每次达到限制时仅将缓冲区的大小加倍对于嵌入式程序来说可能并不理想。

于 2011-09-02T06:49:27.157 回答
0

通常对于嵌入式应用程序,最好分配一个 1-3 倍于最大消息大小的循环 FIFO 缓冲区。

于 2011-09-03T02:32:09.553 回答