我正在尝试优化我的动态内存使用情况 . 问题是我最初为从socket获得的数据分配了一些内存 . 然后,在新数据到达时,我正在重新分配内存,因此新到达的部分将适合本地缓冲区 . 经过一番探讨之后,我发现malloc实际上分配了比请求更多的块 . 在某些情况下显着更大;这里有来自malloc_usable_size(ptr)的一些调试信息:
请求284个字节,分配320个字节请求644个字节,重新分配1024个字节
众所周知,malloc / realloc是昂贵的操作 . 在大多数情况下,新到达的数据将适合先前分配的块(至少当我请求644个byes并获得1024时),但我不知道如何解决这个问题 .
麻烦的是不应该依赖malloc_usable_size(如手册中所述),如果程序请求644字节并且malloc分配1024,则多余的644字节可能被覆盖并且不能安全使用 . 因此,对于给定数量的数据使用malloc然后使用malloc_usable_size来确定实际分配的字节数是不可行的 .
我想要的是在调用malloc之前知道块网格,所以我将准确地请求比我需要的更大的字节数,存储分配的大小和realloc检查我是否真的需要重新分配,或者如果先前分配的块是很好,因为它更大 .
换句话说,如果我要请求644个字节,而malloc实际上给了我1024个,我想预测它并请求1024 .
4 回答
根据您对
libc
的特定实现,您将有不同的行为 . 在大多数情况下,我发现有两种方法可以解决这个问题:mremap
,它可以放大/缩小内存并保证零拷贝 . 它可能会移动您的VM映射 . 这里唯一的问题是它只能在系统页面大小sysconf(_SC_PAGESIZE)
的块中工作,通常是0x1000
.vm_remap
具有与Linux的mremap
类似的语义,但它更加复杂 .简短的回答是标准的malloc界面不提供您正在寻找的信息 . 使用该信息打破了提供的抽象 .
一些替代方案是:
重新考虑您的使用模式 . 也许在开始时预先分配一个缓冲池,随时填充它们 . 不幸的是,这可能会使您的程序比您想要的更复杂 .
使用提供所需接口的其他内存分配库 . 不同的库在碎片,最大运行时间,平均运行时间等方面提供不同的权衡 .
使用您的OS内存分配API . 这些通常被认为是高效的,但通常需要系统调用(与用户空间库不同) .
在我的专业代码中,我经常利用malloc()[etc]分配的
actual size
,而不是requested size
. 这是我确定actual
分配size0的函数:我做了一些痛苦的研究,发现了两个关于Linux和FreeBSD中malloc实现的有趣的事情:
1)在Linux中,malloc以16字节步长线性递增,至少高达8K,因此根本不需要优化,这是不合理的;
2)在FreeBSD中情况不同,步骤更大,并且随着请求的块大小趋于增长 .
因此,只有FreeBSD需要任何类型的优化,因为Linux以非常小的步长分配块,并且它不太可能从套接字接收少于16字节的数据 .