OS X memset 和系统跟踪

Posted

技术标签:

【中文标题】OS X memset 和系统跟踪【英文标题】:OS X memset and system trace 【发布时间】:2015-04-27 19:23:07 【问题描述】:

这是一个简化的程序:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>

void *worker(void *data) 
    size_t size = 1000000;
    void *area = malloc(size);
    if (area != NULL) 
        memset(area, 0, size);
        sleep(1);
        free(area);
    
    return NULL;


int main() 
    int number_of_threads = 4;
    pthread_t threads[number_of_threads];

    for (int i = 0; i < number_of_threads; i++) 
        if (pthread_create(&(threads[i]), NULL, worker, NULL)) 
            return 0;
        
    

    for (int i = 0; i < number_of_threads; i++) 
        pthread_join(threads[i], NULL);
    

    return 0;

我使用命令iprofiler -systemtrace OSXMalloc 得到以下系统跟踪:

为什么memset 会产生所有这些零填充事件?它们是什么意思,为什么这么多?我知道我尝试用零填充 1 MB,但为什么它不在每个线程的一次调用中执行此操作?

【问题讨论】:

【参考方案1】:

您在这里看到的不是memset,而是将页面映射到内存以供以后使用的行为。操作系统用零填充页面,以防止数据从一个应用程序泄漏到另一个应用程序。

您看到的每个零填充事件都会为每个内存页面生成一次。单个内存页面只有 4K 长(4096 字节),因此 100 万字节的连续块跨越 245 个,可能是 246 个单个页面。

可能并非所有内存页面都需要此零填充事件。其中一些可能在空闲 CPU 时间被清零(并且操作系统保留“准备就绪”内存页面的列表),而其他页面可能已分配但从未被使用。但是,在这种情况下,memset 本身会尝试访问每个字节,因此操作系统别无选择,只能在 memset 到达之前清除页面。

【讨论】:

你的回答也很有帮助,因为它有一些细节,你也帮助编辑了问题。谢谢你,很抱歉造成误解。【参考方案2】:

出于安全和隐私的目的,内核需要保证新分配给进程的页面用零填充。否则,您可能会从其他一些流程中获取数据,例如密码或财务信息。

页面在首次访问时归零,有点类似于写时复制。由于memset() 将遍历将它们归零的页面,因此内核将一次将页面归零。 memset() 然后做了一堆多余的工作,在已经归零的页面上写零。

使用calloc() 而不是malloc() 后跟memset(..., 0, ...) 会更好。由于 malloc 库知道内核将零填充新分配的页面,因此它知道不需要执行显式的memset() 来满足calloc() 的零填充合同。第一次访问时仍然会出现零填充错误,但它们会在内存第一次真正被使用时发生。对于不需要的memset(),它们不会“急切地”完成。

顺便说一句,并非所有通过malloc() 完成的分配都从内核获取新页面。有些会重用之前在您的进程中分配和释放的页面。但是,对于像您这样的大型分配,页面通常在 malloc() 期间分配并在 free() 期间释放。

【讨论】:

我想知道零填充的保证是否会导致读者假设“哦,那我真的不必再清除内存了,永远!”所以,提到进程内内存重新分配的好处! (为此,亲爱的读者,它不会填零。)我来这里是为了投票和咀嚼泡泡糖,但今天我已经没有投票了。很快就会回电。 (等等!我还有一个!)【参考方案3】:

将有 4 个线程,每个线程都将调用 malloc 和 memset,因此这 4 个实例已全部占用。

但是,代码中有一个错误。

    pthread_t 数组预设为全零。

    如果对pthread_create 的任何调用失败,请将关联的pthread_t 条目重新设置为0

    如果调用 pthread_create 失败,请不要退出程序

    在调用pthread_join的循环中, 如果关联的pthread_t 条目是0 那么,不要为该条目调用pthread_join

否则,当可能存在活动的 pthread 时,程序将退出。

【讨论】:

首先,这是一个演示程序,仅用于演示系统跟踪输出,您对代码的建议超出了范围。第二件事是我的问题是关于零填充事件的数量。我知道我的代码分配内存并用零填充,谢谢。

以上是关于OS X memset 和系统跟踪的主要内容,如果未能解决你的问题,请参考以下文章

#define _clr(x) memset(x,0xff,sizeof(int)*n) 是啥意思?

c++这个memset()函数有啥用? memset(啥意思,啥意思,啥意思);

STM32中使用strtok,atol,atoi,memset,strlen;后使用atoi系统卡死

实现memset:dl register segfault

memset() 在 while(fgets) 之后

用“零”填充数组-memset()不起作用-[关闭]