据我了解,当被要求保留更大的内存块时,realloc()函数将执行以下三种操作之一:
if free contiguous block exists
grow current block
else if sufficient memory
allocate new memory
copy old memory to new
free old memory
else
return null
增加当前块是一个非常便宜的操作,所以这是我想要利用的行为。但是,如果我正在重新分配内存,因为我想(例如)在现有字符串的开头插入一个char,我不希望realloc()复制内存。我最终会用realloc()复制整个字符串,然后再手动复制它以释放第一个数组元素。
是否可以确定realloc()将执行哪些操作?如果是这样,是否有可能以跨平台的方式实现?
答案 0 :(得分:7)
realloc()
的行为可能取决于其具体实施。并且基于这个代码将是一个可怕的黑客,至少可以说,它违反了封装。
针对您的具体示例的更好解决方案是:
malloc()
),大于前一个缓冲区答案 1 :(得分:2)
如评论中所述,问题中的案例3(无记忆)是错误的;如果没有可用的内存,realloc()
将返回NULL [问题现在已修复]。
realloc()
失败时将realloc()
的返回值保存在原始指针的唯一副本中,那么您只是泄漏了内存。那就是:
void *ptr = malloc(1024);
...
if ((ptr = realloc(ptr, 2048)) == 0)
{
/* Oops - cannot free original memory allocation any more! */
}
realloc()的不同实现将表现不同。唯一安全的假设是总是移动数据 - 当你realloc()内存时,你总是得到一个新地址。
正如其他人所指出的那样,如果您对此感到担心,也许是时候查看您的算法了。
答案 2 :(得分:1)
向后存储字符串会有帮助吗?
...否则 只需要malloc()比你需要的空间更多,当你用完房间时,复制到一个新的缓冲区。一种简单的技术是每次加倍空间;这很好用,因为字符串越大(即复制到新缓冲区所需的时间越多),它发生的频率就越低。
使用此方法,您还可以在缓冲区中对字符串进行右对齐,因此可以轻松地在开头添加字符。
答案 3 :(得分:0)
没有 - 如果你考虑一下,它就行不通。在检查它将要执行的操作和实际操作之间,另一个进程可以分配内存。
在多线程应用程序中,这不起作用。在你检查它将要做什么以及实际做什么之间,另一个线程可以分配内存。
如果您担心这类事情,可能是时候查看您正在使用的数据结构,看看您是否可以解决问题。根据这些字符串的构造方式,您可以使用设计良好的缓冲区高效地完成这些工作。
答案 4 :(得分:0)
我认为这不可能以跨平台的方式进行。 Here是ulibc实现的代码,它可能会让你知道如何以平台相关的方式做到这一点,实际上最好找到glibc源,但这个是谷歌搜索之上:)
答案 5 :(得分:0)
如果obstacks与您的内存分配需求相匹配,则可以使用其fast growing功能。 Obstacks是glibc的一个特性,但它们也可以在libiberty库中使用,它是相当便携的。
答案 6 :(得分:0)
为什么不在字符串的左边保留一些空的缓冲区空间,如下所示:
char* buf = malloc(1024);
char* start = buf + 1024 - 3;
start[0]='t';
start[1]='o';
start[2]='\0';
将“on”添加到字符串的开头,使其“打开\ 0”:
start-=2;
if(start < buf)
DO_MEMORY_STUFF(start, buf);//time to reallocate!
start[0]='o';
start[1]='n';
这样,您不必在每次想要在开头插入时都继续复制缓冲区。
如果必须在开头和结尾都进行插入,只需在两端分配一些空间;显然,中间的插入仍然需要你将元素改组。
答案 7 :(得分:0)
更好的方法是使用链表。让每个数据对象在页面上分配,并从上一页或索引页面分配另一个页面并链接到该页面。通过这种方式,您可以了解下一次分配失败的时间,并且您永远不需要复制内存。