对于一个小型的嵌入式应用程序,我编写了一些函数+ struct作为String Buffer(类似于C ++中的std :: stringstream)。
虽然这样的代码工作正常,但有一些不那么小的问题:
malloc
切换到calloc
,这已经成功删除了警告,但我不完全确定我是否真的在使用它正确我的意思是它分配的内容比实际需要的多(使用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
......看起来不对......
有问题的代码在这里(太大而无法在SO上的<code>
字段中复制):http://codepad.org/LQzphUzd
需要帮助,我很感激任何建议!
答案 0 :(得分:2)
增长缓冲区的方式效率很低。对于每个小字符串,你可以使用realloc()内存,这意味着可以分配新内存并复制“旧”内存的内容。这很慢并且会破坏你的堆。
更好的是以固定数量或固定百分比增长,即使新尺寸为旧尺寸的1.5或2倍。这也浪费了一些内存,但会使堆更有用,而不是那么多副本。
这意味着您必须跟踪两个值:capacity(分配的字节数)和length(字符串的实际长度)。但这不应该太难。
我会介绍一个功能“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);
}
将capacity
乘以1.5,直到data
足够大。您可以根据需要选择不同的策略。
答案 1 :(得分:1)
strncat(ptr->data, str, len);
,在ptr->length = ((ptr->length) + len);
之前移动并使用strncpy(ptr->data+ptr->length...
。而ptr = NULL;
中的Destroy
是没用的。
“库”的代码似乎是正确的但请注意,您不断重新分配缓冲区。通常,您应该尝试很少增长缓冲区(例如,每次需要增长缓冲区时,使用max(2 *当前大小,4)作为新大小),因为增长缓冲区是O(n)。大内存分配可能是因为第一次分配一个小缓冲区。然后在更大的缓冲区中重新分配它。然后你需要在更大的缓冲区中重新分配它,这样堆就会增长。
答案 2 :(得分:0)
看起来你正在为每个追加重新分配缓冲区。只有当你想追求超过它能容纳的东西时,你才能成长吗?
重新分配时,您希望使用一种策略来增加缓冲区的大小,该策略可以在分配数量和分配的内存量之间进行最佳权衡。每次达到限制时,只需将缓冲区大小加倍即可能不适合嵌入式程序。
答案 3 :(得分:0)
通常对于嵌入式应用程序,最好分配1-3倍于最大消息大小的循环FIFO缓冲区。