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

如何确保Box::new()执行堆内存分配?性能测试异常排查

Box::new()堆分配性能测试结果不符合预期的原因及优化禁用方法

优化发生的位置

你的测试结果远低于预期开销,是编译器优化和内存分配器缓存共同作用的结果:

  1. Rust编译器的Release模式优化
    若你使用cargo run --release运行代码,编译器会启用全量优化(默认opt-level=3):

    • 循环展开:将10万次循环拆分为更大批次执行,减少循环条件判断的额外开销,让累加和堆分配的实际执行占比更高。
    • 小对象分配优化:Box::new(42)分配的是固定大小的i32(4字节),编译器会针对这类小对象生成更高效的分配代码,甚至和分配器配合简化流程。
  2. 内存分配器的缓存机制
    Rust默认使用的内存分配器(如jemalloc或新版本系统分配器)会维护小对象内存缓存池:
    每次调用Box::new时,分配器无需向操作系统申请新内存页,直接从缓存池中取出空闲内存块,分配速度大幅提升。即便你用Box::leak泄漏内存,在缓存池耗尽前,分配器依然能快速提供内存块。

如何禁用这些优化

要看到堆分配的真实开销,可从以下两方面操作:

1. 禁用编译器优化

使用Debug模式编译运行代码(默认即为Debug模式,无需加--release参数),或在Cargo.toml中强制设置优化等级为0:

[profile.release]
opt-level = 0

Debug模式下,编译器会关闭几乎所有优化:循环不会展开,每个迭代都执行完整流程,Box::new的代码保留最原始的调用路径,能真实反映单步堆分配的开销。

2. 绕过分配器缓存

若想彻底绕过分配器缓存,直接测试向操作系统申请内存的开销,可手动调用系统级内存分配函数(通过libc库调用mmap):

use std::time::Instant;
use libc::{mmap, PROT_READ, PROT_WRITE, MAP_ANONYMOUS, MAP_PRIVATE};

fn main() {
    let start = Instant::now();
    let mut sum = 0;
    for _ in 0..100000 {
        sum += 42;
    }
    println!("Simple sum: {:?}", start.elapsed());

    let start2 = Instant::now();
    for _ in 0..100000 {
        // 直接调用mmap申请4字节内存,绕过分配器缓存
        let ptr = unsafe {
            mmap(
                std::ptr::null_mut(),
                4,
                PROT_READ | PROT_WRITE,
                MAP_ANONYMOUS | MAP_PRIVATE,
                -1,
                0,
            )
        };
        if ptr == libc::MAP_FAILED {
            panic!("mmap failed");
        }
    }
    println!("Direct syscall alloc: {:?}", start2.elapsed());
}

这种方式每次都会向操作系统申请新的匿名内存块,能体现堆分配的真实系统开销,此时你会看到它与累加操作的差距远大于5倍。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 13:07:42