【发布时间】:2010-08-15 14:44:35
【问题描述】:
我需要将文件中不同大小的记录归零。为此,我目前正在分配虚拟记录,memset将它们归零,并将它们传递给写入函数。
是否有一些区域可以保证总是归零(并且大小足够大),而我可以指向它,从而无需重复分配和归零内存?
【问题讨论】:
标签: c optimization malloc memset
我需要将文件中不同大小的记录归零。为此,我目前正在分配虚拟记录,memset将它们归零,并将它们传递给写入函数。
是否有一些区域可以保证总是归零(并且大小足够大),而我可以指向它,从而无需重复分配和归零内存?
【问题讨论】:
标签: c optimization malloc memset
如果记录大小有合理的上限,请分配一个包含零的全局只读变量。 (因为它是一个静态持续时间对象,它会自动初始化为零。)
const unsigned char zero_filled_buffer[MAX_RECORD_SIZE]; /*at file scope*/
如果写入函数是 C fwrite 或 POSIX write 或其他函数,您可以(必须,对于 write)在循环中调用它,因此缓冲区不必像最大的记录,和你一次写的最大块一样大。
在典型的托管实现下,这样的变量将在您的可执行文件中占用零空间。 添加:请注意,就 C 标准而言,上面的声明与 const unsigned char zero_filled_buffer[MAX_RECORD_SIZE] = {0}; 完全相同,但是如果您显式添加 = {0},某些编译器(包括 gcc)会在可执行文件中包含零但如果您不使用初始化程序,则不会。
具有虚拟内存的系统上的智能程序加载器可以利用虚拟内存系统为所有此类对象使用物理 RAM 的单个共享只读零填充页面;不知道有没有实际操作。 添加:例如,Linux (Debian lenny amd64) 没有。
另一种 POSIX 方法是 mmap 文件并调用 memset 以清零缓冲区。
【讨论】:
= {0}放在上面
.data 或 .bss 中。
static const ...
见calloc。
calloc()函数应为nelem元素的数组分配未使用的空间,每个元素的字节大小为elsize。空间应初始化为所有位0。
或者(我没有尝试过),如果您根本不想要 任何 分配,您可以 open 和/或 mmap /dev/zero 并读取 record_size 块并将它们写入要覆盖记录的文件中。
【讨论】:
calloc分配一次并使用它。
至少在linux上通过mmap()分配内存会给你一个零填充的缓冲区。
缺点是您不能只分配所需的内存,而只能分配页面大小的倍数
#include <unistd.h>
long sz = sysconf(_SC_PAGESIZE);
【讨论】:
是的,只需为任何这些记录分配一个足够大的块,然后将其归零一次。每次都将该块的地址传递给您的写入函数,其中记录的大小是您实际想要清零的记录。将缓冲区传递给写入不会使其过期或任何事情。请注意, write 也不会释放您传递的缓冲区;这取决于你。
【讨论】:
如果您想要一个始终为零的大内存区域,您应该自己分配它并将其 memset 为零。没有解决这个问题,但你应该只需要做一次。确保它至少与您在任何时候需要的最大归零内存一样大。
然后,当您需要将指针传递给归零内存时,您可以将指针传递给您分配的这个块。
【讨论】:
如前所述,您只需分配一次您将需要的最大区域;您可以在任何需要该大小或更小的区域时传递它。
在大多数实现中,地址空间的任何部分都没有映射到 RAM,但在读取时会无害地读取零。拥有这样的东西可能很好,但我不知道有一个。
在一些嵌入式系统中,我编写了闪存写入例程,因此,如果给定一个空指针,它们将假定源数据(取决于应用程序)都是 FF,因为有时我确实需要清除一个文件的一个块,并且让最终的写入代码处理空指针情况意味着查找和分配闪存块的代码可以在写有意义的数据情况和写空白数据的情况之间共享。需要注意的是,如果将写入拆分为多个部分,则不得在将空指针传递给 I/O 写入之前将偏移量添加到空指针。
【讨论】:
使用系统信息API获取系统页面大小(我只是不记得确切的名称),分配1页内存,将其设置为零,一遍又一遍地顺序写入。
【讨论】:
mmap 它是只读的。
write 函数的速度将比 memset 慢几个数量级。
分析它!
* 即使使用闪存驱动器
【讨论】:
这是保证工作的运行时可能性(使用gcc zeroed_mem_region.c -Wall -std=gnu99 编译):
#include <sys/mman.h>
#include <assert.h>
#include <stdio.h>
size_t const zeroed_size = 512;
char const *zeroed;
int main()
{
zeroed = mmap(
NULL,
zeroed_size,
PROT_READ,
MAP_PRIVATE|MAP_ANONYMOUS,
-1,
0);
printf("zeroed region at %p\n", zeroed);
for (size_t i = 0; i < zeroed_size; ++i) {
assert(zeroed[i] == 0);
}
printf("testing for writability\n");
((char *)zeroed)[0] = 1;
return 0;
}
请注意,用于测试的归零是 char const *,实际上这将是 void const *。
SIGSEGV)mmap(2))【讨论】:
const zeroed[](gcc 在我的机器上可写);另一方面,如果您直接分配,const zeroed[] 会在 gcc 中出现编译时错误。可执行文件中没有废话也适用于静态持续时间const zeroed[]。另一个专业人士能够在运行时选择尺寸。 MAP_ANON 不是 POSIX,但在现代 unice 上广泛可用。 const zeroed[] 和 mmap 都不够聪明,无法在我的机器 (Linux/amd64) 上一遍又一遍地分配相同的物理页面(不过对于 512B 来说不是问题)。