将指针传递给保证归零的内存

时间:2010-08-15 14:44:35

标签: c optimization malloc memset

我需要将文件中不同大小的记录归零。为此,我正在分配虚拟记录,memset将它们归零,并将它们传递给写入函数。

是否有一些区域可以保证始终为零(并且大小足够大),我可以反而指出,不需要重复分配和清零内存?

9 个答案:

答案 0 :(得分:8)

如果记录大小有合理的上限,则分配一个包含零的全局只读变量。 (因为它是一个静态持续时间对象,它会自动初始化为零。)

const unsigned char zero_filled_buffer[MAX_RECORD_SIZE]; /*at file scope*/

如果write函数是C fwrite或POSIX write或其他函数,则可以(对于write必须)在循环中调用它,因此缓冲区不会必须像最大的记录一样大,就像你一次写的最大块一样大。

在典型的托管实现下,这样的变量将在可执行文件中占用零空间。 ADDED :请注意,就C标准而言,上面的声明与const unsigned char zero_filled_buffer[MAX_RECORD_SIZE] = {0};完全等效,但是如果您明确添加{,则某些编译器(包括gcc)在可执行文件中包含零。 {1}}但如果您不使用初始化程序则不会。

具有虚拟内存的系统上的智能程序加载器可以利用虚拟内存系统为所有此类对象使用物理RAM的单个共享只读零填充页面;我不知道在实践中是否有任何做法。 ADDED :例如,Linux(Debian lenny amd64)没有。

另一种POSIX方法是= {0}文件并调用mmap以填充缓冲区。

答案 1 :(得分:3)

请参阅calloc

  

calloc()函数应为nelem个数组分配未使用的空间,每个元素的大小为字节elsize。该空间应初始化为所有位0

或者(我没试过),如果你根本不想要任何分配,你可以open和/或mmap /dev/zero和从中读取record_size个块并将它们写入您覆盖记录的文件中。

答案 2 :(得分:2)

至少在linux上通过mmap()分配内存会给你一个零填充缓冲区。 缺点是您不能只分配所需的内存,而只能分配页面大小的倍数

#include <unistd.h>
long sz = sysconf(_SC_PAGESIZE);

答案 3 :(得分:1)

是的,只需为这些记录分配足够大的块,并将其归零一次。每次都将该块的地址传递给您的写入函数,其中包含您实际想要清零的记录的大小。传递缓冲区进行写入不会使其过期或任何事情。记住你,写也不释放你传递的缓冲区;这取决于你。

答案 4 :(得分:1)

如果你想要一个总是归零的大区域内存,你应该自己分配它并将其memset为零。没有解决这个问题,但你应该只做一次。确保它至少与您在任何时候需要的最大归零内存量一样大。

然后,只要您需要将指针传递给归零内存,就可以将指针传递到您分配的此块中。

答案 5 :(得分:1)

如上所述,您只需要分配一次您需要的最大区域;你可以在任何需要大小或更小的区域的时候通过它。

在大多数实现中,没有地址空间的任何部分没有映射到RAM,但是当读取时无害地读取零。这样的事情可能会很好,但我不知道一个。

在某些嵌入式系统中,我编写了闪存写入例程,因此,如果给出空指针,他们将假设源数据(取决于应用程序)所有FF,因为我有时需要清除一个文件的块,并且最后的写代码处理空指针的情况意味着可以在写有意义数据情况和写空数据情况之间共享用于查找和分配闪存块的代码。需要注意的是,如果将写入分成多个部分,则必须在将空指针传递给I / O写入之前不要向空指针添加偏移量。

答案 6 :(得分:0)

使用系统信息API获取系统页面大小(我只是记不清确切的名称),分配1页内存,将其设置为零,一遍又一遍地写入。

答案 7 :(得分:0)

写入功能的速度将比memset慢几个数量级。

简介!

*即使使用闪存驱动器

答案 8 :(得分:0)

这是一种保证工作,运行时可能性(使用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 *

赞成

  • 避免使用malloc allocator
  • 保证区域不可写(生成SIGSEGV
  • 比使用malloc更快
  • 不会将垃圾放入可执行文件
  • 无需memset步骤(选中mmap(2)

缺点

  • Unix / Linux特定(自Linux 2.4以来的匿名映射)
  • 减少了编译器优化的可能性(虽然这个区域显然没有)