You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

初始化与未初始化值性能测试的有效性及结果可信度问询

初始化与未初始化内存的性能测试疑问与分析

测试背景

我看到不同视频对初始化值与未初始化值的性能差异说法完全相反,于是自己编写了C语言测试代码验证。

测试代码

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>

void a(int size) {
    int* a = malloc(sizeof(int) * size);
    memset(a, 0, sizeof(int) * size);
    for(int i = 0; i < size; i++) {
        a[i] = i;
    }
    free(a);
}
void b(int size) {
    int* a = malloc(sizeof(int) * size);
    for(int i = 0; i < size; i++) {
        a[i] = i;
    }
    free(a);
}
int test(void fun(int), int runs, int size) {
    int time = 0;
    for(int i = 0; i < runs; i++) {
        struct timeval beg = {0}, end = {0};
        gettimeofday(&beg, NULL);
        fun(size);
        gettimeofday(&end, NULL);
        int usec_diff = end.tv_usec - beg.tv_usec;
        if(usec_diff < 0) {
            time += 1000000;
        } else {
            time += usec_diff;
        }
    }
    return time;
}
int main() {
    int a_3 = test(&a, 100000, 1000);
    int b_3 = test(&b, 100000, 1000);
    printf("b/a ^3: %f\n", (float)b_3 / a_3);
    int a_4 = test(&a, 100000, 10000);
    int b_4 = test(&b, 100000, 10000);
    printf("b/a ^4: %f\n", (float)b_4 / a_4);
    int a_5 = test(&a, 100000, 100000);
    int b_5 = test(&b, 100000, 100000);
    printf("b/a ^5: %f\n", (float)b_5 / a_5);
}

测试结果

eck@eck:~/src/test$ ./main
b/a ^3: 2.764046
b/a ^4: 0.989866
b/a ^5: 0.990233

核心疑问

  • 首次编写这类性能测试,想确认测试是否合理、结果是否可信
  • 开启-O1优化后,两个函数生成的汇编代码完全相同,想了解复杂场景下的情况,以及初始化值与未初始化值的性能差异究竟如何

测试合理性与结果可信度分析

  1. 测试的合理性

    • 你的测试框架具备基础计时逻辑,但存在几个可优化细节:
      • 计时逻辑有漏洞:只计算了tv_usec的差值,未处理tv_sec的跨秒情况,正确耗时计算应为(end.tv_sec - beg.tv_sec)*1000000 + (end.tv_usec - beg.tv_usec)
      • 缺少预热步骤:循环测试前应先调用几次测试函数,让CPU缓存、内存页表进入稳定状态,避免前几次调用的干扰
      • 测试参数可调整:小内存(1000个int,4KB)跑100000次易被操作系统内存缓存过度优化,大内存测试次数可适当减少以缩短测试时间
    • 结果趋势可信:小内存下未初始化版本耗时更高,大内存下两者性能接近,符合操作系统内存管理的实际机制
  2. -O1优化后汇编相同的原因

    • 编译器会执行冗余操作消除:你的代码中memset初始化的内存被后续for循环完全覆盖,编译器能识别出memset是无用操作,直接将其删除,因此两个函数的汇编代码完全一致
    • 这种优化仅在“初始化操作被后续写操作完全覆盖”的场景生效,如果初始化后有读操作、或后续写操作未覆盖全部初始化区域,编译器不会消除memset

初始化与未初始化内存的性能差异本质

  1. 小内存场景(如4KB)

    • 操作系统内存页通常为4KB,小内存刚好占一页。malloc返回的未初始化内存采用懒加载机制:只有第一次写入时才会触发缺页中断分配物理页
    • 而memset会提前触发缺页中断完成物理页分配,后续for循环写入时无需再触发中断。因此小内存下未初始化版本因额外的缺页中断,总耗时更高,对应你看到的b/a≈2.7
  2. 大内存场景(如400KB、4MB)

    • 内存超过一定大小后,无论是否初始化,都会触发大量缺页中断。此时memset的开销相对于缺页中断可忽略,或操作系统的预分配机制会抹平两者差异,因此b/a接近1
  3. 复杂场景下的差异

    • 若初始化后存在读操作:未初始化内存可能因读取随机值导致分支预测失败,或因未分配物理页触发缺页中断,性能更差
    • 若内存多次复用(如free后再次malloc):未初始化内存可能是已分配的热页,此时初始化的开销会比首次malloc时更明显
    • 实时或延迟敏感场景:未初始化内存的缺页中断会带来不可预测的延迟,而初始化可提前加载内存页,保证延迟稳定

内容的提问来源于stack exchange,提问作者ashton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 08:25:08