Skip to content

Latest commit

 

History

History
552 lines (430 loc) · 25.9 KB

File metadata and controls

552 lines (430 loc) · 25.9 KB

测试数据分析

测试环境

在华为云进行测试,8核心(4个物理核心开启超线程技术)

15G内存,40G硬盘

root@ecs-ec4a:~/cppMemoryPool# lscpu
Architecture:                x86_64
  CPU op-mode(s):            32-bit, 64-bit
  Address sizes:             42 bits physical, 48 bits virtual
  Byte Order:                Little Endian
CPU(s):                      8
  On-line CPU(s) list:       0-7
Vendor ID:                   AuthenticAMD
  Model name:                General Purpose Processor
    CPU family:              25
    Model:                   1
    Thread(s) per core:      2
    Core(s) per socket:      4
    Socket(s):               1
    Stepping:                1
    BogoMIPS:                4899.99
    Flags:                   fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm const
                             ant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_tim
                             er aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext perfctr_core invpcid_single ssbd
                              ibrs ibpb stibp vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves clz
                             ero xsaveerptr wbnoinvd arat umip vaes vpclmulqdq fsrm arch_capabilities
Virtualization features:     
  Hypervisor vendor:         KVM
  Virtualization type:       full
Caches (sum of all):         
  L1d:                       128 KiB (4 instances)
  L1i:                       128 KiB (4 instances)
  L2:                        2 MiB (4 instances)
  L3:                        32 MiB (1 instance)
NUMA:                        
  NUMA node(s):              1
  NUMA node0 CPU(s):         0-7
Vulnerabilities:             
  Gather data sampling:      Not affected
  Indirect target selection: Not affected
  Itlb multihit:             Not affected
  L1tf:                      Not affected
  Mds:                       Not affected
  Meltdown:                  Not affected
  Mmio stale data:           Not affected
  Reg file data sampling:    Not affected
  Retbleed:                  Not affected
  Spec rstack overflow:      Mitigation; safe RET, no microcode
  Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl and seccomp
  Spectre v1:                Mitigation; usercopy/swapgs barriers and __user pointer sanitization
  Spectre v2:                Mitigation; Retpolines; IBPB conditional; IBRS_FW; STIBP conditional; RSB filling; PBRSB-eIBRS Not affected; BHI Not affected
  Srbds:                     Not affected
  Tsa:                       Vulnerable: Clear CPU buffers attempted, no microcode
  Tsx async abort:           Not affected
  Vmscape:                   Not affected
root@ecs-ec4a:~/cppMemoryPool# 
root@ecs-ec4a:~/cppMemoryPool# free -h
               total        used        free      shared  buff/cache   available
Mem:            15Gi       707Mi        13Gi       2.0Mi       834Mi        14Gi
Swap:             0B          0B          0B
root@ecs-ec4a:~/cppMemoryPool# df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           1.6G  1.1M  1.6G   1% /run
/dev/vda1        40G  6.6G   31G  18% /
tmpfs           7.7G     0  7.7G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           1.6G  4.0K  1.6G   1% /run/user/0
root@ecs-ec4a:~/cppMemoryPool# 

测试数据分析

googlebenchmark基准测试

测试代码

#include <benchmark/benchmark.h>
#include "memory.hpp"
#include <cstdlib>
#include <mutex>
#include <vector>

// 保持与你 memory.hpp 中一致的块大小
constexpr std::size_t BLOCK_SIZE = 64; 
constexpr std::size_t BATCH_SIZE = 32; // 模拟真实的批量业务流

// 全局内存池指针和初始化标记
static FixedSizeMemory* g_pool = nullptr;
static std::once_flag g_pool_init_flag;

// 保证全局池只被安全地初始化一次
void InitGlobalPool() {
    // 假设你的构造函数只接收 block_size,或者有默认的 blocks_per_page
    g_pool = new FixedSizeMemory(BLOCK_SIZE);
}

// ==================== 1. 自定义内存池批量跑分 ====================
static void BM_CustomMemoryPool(benchmark::State& state) {
    // 安全地进行单次初始化
    std::call_once(g_pool_init_flag, InitGlobalPool);

    // 局部数组,用来存放批量申请的指针
    void* ptrs[BATCH_SIZE];

    // 跑分主循环
    for (auto _ : state) {
        // 步骤一:批量分配,让第一级 TLS 无锁路径吃满缓存
        for (std::size_t i = 0; i < BATCH_SIZE; ++i) {
            ptrs[i] = g_pool->allocate();
        }
        
        // 防止编译器把分配动作优化掉
        benchmark::DoNotOptimize(ptrs);
        
        // 步骤二:批量释放,触发本地缓存高水位积攒,绕开高频锁冲突
        for (std::size_t i = 0; i < BATCH_SIZE; ++i) {
            g_pool->deallocate(ptrs[i]);
        }
        
        // 刷新内存状态
        benchmark::ClobberMemory();
    }

    // 线程退出前,看门人兜底之外,强制刷新归还当前线程本地缓存
    g_pool->flush_thread_cache();
}
// 注册测试,覆盖 1, 4, 8, 16 核心线程压测
BENCHMARK(BM_CustomMemoryPool)->ThreadRange(1, 16)->UseRealTime();


// ==================== 2. 对照组:原生 malloc / free 跑分 ====================
static void BM_SystemMalloc(benchmark::State& state) {
    void* ptrs[BATCH_SIZE];

    for (auto _ : state) {
        for (std::size_t i = 0; i < BATCH_SIZE; ++i) {
            ptrs[i] = std::malloc(BLOCK_SIZE);
        }
        
        benchmark::DoNotOptimize(ptrs);
        
        for (std::size_t i = 0; i < BATCH_SIZE; ++i) {
            std::free(ptrs[i]);
        }
        
        benchmark::ClobberMemory();
    }
}
BENCHMARK(BM_SystemMalloc)->ThreadRange(1, 16)->UseRealTime();

// 自动生成含有 Google Benchmark 逻辑的 main 函数入口
BENCHMARK_MAIN();

测试数据

root@ecs-ec4a:~/cppMemoryPool/build# ./pool_bench 
2026-07-29T23:30:51+08:00
Running ./pool_bench
Run on (8 X 2449.74 MHz CPU s)
CPU Caches:
  L1 Data 32 KiB (x4)
  L1 Instruction 32 KiB (x4)
  L2 Unified 512 KiB (x4)
  L3 Unified 32768 KiB (x1)
Load Average: 0.07, 0.05, 0.00
-----------------------------------------------------------------------------------
Benchmark                                         Time             CPU   Iterations
-----------------------------------------------------------------------------------
BM_CustomMemoryPool/real_time/threads:1         164 ns          164 ns      4233756
BM_CustomMemoryPool/real_time/threads:2        82.0 ns          164 ns      8468594
BM_CustomMemoryPool/real_time/threads:4        41.1 ns          164 ns     16722248
BM_CustomMemoryPool/real_time/threads:8        40.5 ns          323 ns     17197008
BM_CustomMemoryPool/real_time/threads:16       38.5 ns          322 ns     21816688
BM_SystemMalloc/real_time/threads:1             528 ns          528 ns      1324934
BM_SystemMalloc/real_time/threads:2             266 ns          531 ns      2631462
BM_SystemMalloc/real_time/threads:4             133 ns          532 ns      5256160
BM_SystemMalloc/real_time/threads:8             128 ns         1018 ns      5496872
BM_SystemMalloc/real_time/threads:16            121 ns         1016 ns      7249680
root@ecs-ec4a:~/cppMemoryPool/build# 

指标定义分析

核心定义

  • 1 次配对操作(Allocation Pair):即 1 次 allocate() + 1 次 deallocate()。在实际业务中,申请了内存就必须释放,因此以“完整生命周期”为单位最符合业务逻辑。

  • 全系统总 QPS(System-wide Throughput)

    $$\text{全系统 QPS} = \text{所有线程在 1 秒内共同完成的【配对操作】总次数}$$

  • 单次配对延迟(Per-Pair Latency)

    $$\text{单次配对延迟} = \frac{\text{线程数}}{\text{全系统 QPS}}$$

线程数 Real Time (单次 Iteration 耗时) 解释说明 全系统总 QPS 单次 [分配+释放] 延迟 预估单次 allocate() 延迟
1 线程 164.0 ns 单核无竞争 1.95 亿 ops/s 5.12 ns 2.56 ns
2 线程 82.0 ns 物理多核并行 7.80 亿 ops/s 2.56 ns 1.28 ns
4 线程 41.1 ns 物理 4 核吃满 31.14 亿 ops/s 1.28 ns 0.64 ns
8 线程 40.5 ns 8 逻辑核(开启超线程) 63.21 亿 ops/s 1.27 ns 0.63 ns
16 线程 38.5 ns 超出逻辑核(时钟抢占) 132.98 亿 ops/s 1.20 ns 0.60 ns

长时间运行测试

测试代码

#include "memory.hpp"
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
#include <atomic>
#include <random>
#include <cassert>
#include <fstream>
#include <string>
#include <iomanip>

#include <unistd.h>

// 魔法数,用于检测内存踩踏(Corruption)
constexpr uint32_t MAGIC_NUMBER = 0xDEADBEEF;

struct Payload {
    uint32_t magic;
    uint32_t thread_id;
    uint64_t seq;
    char dummy[16]; // 填充数据,保证 Payload 体积
};

// 获取当前进程物理内存占用 (RSS, 单位: MB)
double get_process_rss_mb() {
    std::ifstream statm("/proc/self/statm");
    if (!statm.is_open()) return 0.0;
    long pages = 0;
    long rss_pages = 0;
    statm >> pages >> rss_pages;
    long page_size_kb = sysconf(_SC_PAGESIZE) / 1024;
    return (rss_pages * page_size_kb) / 1024.0;
}

// 模拟真实高压业务的工作线程
void worker_thread(FixedSizeMemory& pool, int thread_id, std::atomic<bool>& stop_flag, std::atomic<uint64_t>& total_ops) {
    std::mt19937 rng(1337 + thread_id);

    constexpr std::size_t MAX_HOLD = 1024;
    std::vector<Payload*> held_ptrs;
    held_ptrs.reserve(MAX_HOLD);

    uint64_t local_seq = 0;

    while (!stop_flag.load(std::memory_order_relaxed)) {
        // 1. 批量分配内存 (1 ~ 32 块)
        std::size_t batch_size = (rng() % 32) + 1;
        for (std::size_t i = 0; i < batch_size; ++i) {
            void* p = pool.allocate();
            if (p != nullptr) {
                Payload* payload = new (p) Payload(); // placement new
                payload->magic = MAGIC_NUMBER;
                payload->thread_id = static_cast<uint32_t>(thread_id);
                payload->seq = ++local_seq;
                held_ptrs.push_back(payload);
            }
        }

        total_ops.fetch_add(batch_size, std::memory_order_relaxed);

        // 2. 随机决定是“释放部分内存”还是“继续持有”(制造动态水位波动)
        if (!held_ptrs.empty()) {
            // 如果手里的内存堆积太多(超过 512),优先大比例释放
            std::size_t release_count = (held_ptrs.size() > 512) ? 
                                         held_ptrs.size() / 2 : 
                                         (rng() % (held_ptrs.size() + 1));

            for (std::size_t i = 0; i < release_count; ++i) {
                Payload* payload = held_ptrs.back();
                held_ptrs.pop_back();

                // 踩内存校验:如果 Magic 被篡改,直接崩溃
                assert(payload->magic == MAGIC_NUMBER && "内存发生数据越界/踩内存!");
                
                payload->~Payload();
                pool.deallocate(payload);
            }
        }

        // 3. 极短让出 CPU,模拟真实业务微小停顿
        if (rng() % 10 == 0) {
            std::this_thread::yield();
        }
    }

    // 4. 线程退出前,把手里剩下的全部释放干净
    for (Payload* payload : held_ptrs) {
        assert(payload->magic == MAGIC_NUMBER && "内存发生数据越界/踩内存!");
        payload->~Payload();
        pool.deallocate(payload);
    }
    held_ptrs.clear();

    // 手动刷新该线程的 TLS 缓存到 Page 中,确保退出时不残留
    pool.flush_thread_cache();
}

int main(int argc, char* argv[]) {
    // 默认跑 600 秒 (10分钟),命令行传参可指定跑多久
    int duration_seconds = 600;
    if (argc > 1) {
        duration_seconds = std::atoi(argv[1]);
    }

    std::cout << "==========================================================================" << std::endl;
    std::cout << "        内存池长跑稳定性 + 分段 QPS 性能衰退监测 (Soak Testing) " << std::endl;
    std::cout << " 压测时长: " << duration_seconds << "" << std::endl;
    std::cout << "==========================================================================" << std::endl;

    // 创建单块 64 字节,每页 1024 块的内存池
    FixedSizeMemory pool(64, 1024);

    unsigned int num_threads = std::thread::hardware_concurrency();
    if (num_threads == 0) num_threads = 4;
    std::cout << "启动压测线程数: " << num_threads << std::endl;

    std::atomic<bool> stop_flag{false};
    std::atomic<uint64_t> total_ops{0};
    std::vector<std::thread> workers;

    // 启动后台监控线程:每 10 秒监控一次分段 QPS 与内存占用
    std::thread monitor_thread([&]() {
        auto start_time = std::chrono::steady_clock::now();
        uint64_t last_ops = 0;

        while (!stop_flag.load(std::memory_order_relaxed)) {
            // 每 10 秒统计一次区间 QPS
            std::this_thread::sleep_for(std::chrono::seconds(10));
            auto now = std::chrono::steady_clock::now();
            auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - start_time).count();

            uint64_t current_ops = total_ops.load(std::memory_order_relaxed);
            uint64_t interval_ops = current_ops - last_ops;
            double current_qps = interval_ops / 10.0; // 过去 10 秒内的平均 QPS
            last_ops = current_ops;

            double rss_mb = get_process_rss_mb();
            std::size_t active_allocs = pool.allocated_count();
            std::size_t pages = pool.page_count();

            std::cout << "[" << std::setw(4) << elapsed << "s] "
                      << "区间QPS: " << std::setw(12) << static_cast<uint64_t>(current_qps) << " ops/s | "
                      << "累计操作: " << std::setw(12) << current_ops << " | "
                      << "活动块: " << std::setw(5) << active_allocs << " | "
                      << "Page数: " << std::setw(3) << pages << " | "
                      << "RSS内存: " << std::fixed << std::setprecision(2) << rss_mb << " MB"
                      << std::endl;
        }
    });

    // 启动所有工作线程
    for (unsigned int i = 0; i < num_threads; ++i) {
        workers.emplace_back(worker_thread, std::ref(pool), i, std::ref(stop_flag), std::ref(total_ops));
    }

    // 主线程等待压测倒计时结束
    std::this_thread::sleep_for(std::chrono::seconds(duration_seconds));

    // 通知所有线程平滑退出
    std::cout << "\n压测时间到,正在通知所有线程平滑退出并刷新 TLS..." << std::endl;
    stop_flag.store(true, std::memory_order_relaxed);

    for (auto& t : workers) {
        if (t.joinable()) t.join();
    }

    if (monitor_thread.joinable()) {
        monitor_thread.join();
    }

    std::cout << "\n================ 最终收尾与内存泄漏验证 ================" << std::endl;
    std::cout << "总完成操作次数  : " << total_ops.load() << std::endl;
    std::cout << "当前未归还内存块: " << pool.allocated_count() << std::endl;
    std::cout << "最终申请 Page 数: " << pool.page_count() << std::endl;

    // 终极断言:所有线程退出并 flush TLS 后,未归还分配数必须严格归零!
    if (pool.allocated_count() == 0) {
        std::cout << " SUCCESS: 长跑压测通过!0 内存泄漏,0 数据损坏,性能平稳!" << std::endl;
    } else {
        std::cerr << " ERROR: 压测失败!检测到内存泄漏!未归还块数: " << pool.allocated_count() << std::endl;
        return 1;
    }

    return 0;
}

测试数据

nohup: ignoring input
==========================================================================
        内存池长跑稳定性 + 分段 QPS 性能衰退监测 (Soak Testing) 
 压测时长: 600 秒
==========================================================================
启动压测线程数: 8
[  10s] 区间QPS:    389378654 ops/s | 累计操作:   3893786547 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[  20s] 区间QPS:    389411745 ops/s | 累计操作:   7787903997 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[  30s] 区间QPS:    390512243 ops/s | 累计操作:  11693026433 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[  40s] 区间QPS:    389701668 ops/s | 累计操作:  15590043122 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[  50s] 区间QPS:    389770212 ops/s | 累计操作:  19487745247 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[  60s] 区间QPS:    390288194 ops/s | 累计操作:  23390627188 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[  70s] 区间QPS:    389563709 ops/s | 累计操作:  27286264286 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[  80s] 区间QPS:    389542351 ops/s | 累计操作:  31181687799 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[  90s] 区间QPS:    390058793 ops/s | 累计操作:  35082275733 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 100s] 区间QPS:    390313934 ops/s | 累计操作:  38985415079 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 110s] 区间QPS:    389892869 ops/s | 累计操作:  42884343773 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 120s] 区间QPS:    390047514 ops/s | 累计操作:  46784818913 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 130s] 区间QPS:    389504280 ops/s | 累计操作:  50679861714 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 140s] 区间QPS:    389901886 ops/s | 累计操作:  54578880581 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 150s] 区间QPS:    390429693 ops/s | 累计操作:  58483177512 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 160s] 区间QPS:    390338964 ops/s | 累计操作:  62386567153 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 170s] 区间QPS:    390200460 ops/s | 累计操作:  66288571755 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 180s] 区间QPS:    390500037 ops/s | 累计操作:  70193572130 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 190s] 区间QPS:    389901181 ops/s | 累计操作:  74092583940 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 200s] 区间QPS:    389379158 ops/s | 累计操作:  77986375529 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 210s] 区间QPS:    390794075 ops/s | 累计操作:  81894316284 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 220s] 区间QPS:    390596642 ops/s | 累计操作:  85800282705 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 230s] 区间QPS:    390166316 ops/s | 累计操作:  89701945867 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 240s] 区间QPS:    390626278 ops/s | 累计操作:  93608208655 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 250s] 区间QPS:    390326427 ops/s | 累计操作:  97511472925 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 260s] 区间QPS:    389842223 ops/s | 累计操作: 101409895161 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 270s] 区间QPS:    390673486 ops/s | 累计操作: 105316630029 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 280s] 区间QPS:    390550282 ops/s | 累计操作: 109222132854 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 290s] 区间QPS:    390235222 ops/s | 累计操作: 113124485075 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 300s] 区间QPS:    390827430 ops/s | 累计操作: 117032759376 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 310s] 区间QPS:    389852471 ops/s | 累计操作: 120931284095 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 320s] 区间QPS:    390444219 ops/s | 累计操作: 124835726294 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 330s] 区间QPS:    390644064 ops/s | 累计操作: 128742166935 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 340s] 区间QPS:    390716592 ops/s | 累计操作: 132649332861 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 350s] 区间QPS:    390615132 ops/s | 累计操作: 136555484187 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 360s] 区间QPS:    390480129 ops/s | 累计操作: 140460285477 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 370s] 区间QPS:    390037826 ops/s | 累计操作: 144360663742 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 380s] 区间QPS:    390228243 ops/s | 累计操作: 148262946173 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 390s] 区间QPS:    390519860 ops/s | 累计操作: 152168144775 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 400s] 区间QPS:    390632474 ops/s | 累计操作: 156074469523 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 410s] 区间QPS:    390515007 ops/s | 累计操作: 159979619602 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 420s] 区间QPS:    390556951 ops/s | 累计操作: 163885189121 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 430s] 区间QPS:    389863889 ops/s | 累计操作: 167783828011 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 440s] 区间QPS:    390131324 ops/s | 累计操作: 171685141260 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 450s] 区间QPS:    390116021 ops/s | 累计操作: 175586301478 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 460s] 区间QPS:    390242640 ops/s | 累计操作: 179488727881 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 470s] 区间QPS:    389877631 ops/s | 累计操作: 183387504197 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 480s] 区间QPS:    389350833 ops/s | 累计操作: 187281012527 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 490s] 区间QPS:    390128285 ops/s | 累计操作: 191182295384 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 500s] 区间QPS:    390386441 ops/s | 累计操作: 195086159797 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 510s] 区间QPS:    390374202 ops/s | 累计操作: 198989901826 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 520s] 区间QPS:    390599641 ops/s | 累计操作: 202895898238 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 530s] 区间QPS:    390546578 ops/s | 累计操作: 206801364027 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 540s] 区间QPS:    390427997 ops/s | 累计操作: 210705643997 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 550s] 区间QPS:    390017848 ops/s | 累计操作: 214605822481 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 560s] 区间QPS:    390136596 ops/s | 累计操作: 218507188441 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 570s] 区间QPS:    390206555 ops/s | 累计操作: 222409253991 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 580s] 区间QPS:    390478279 ops/s | 累计操作: 226314036782 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB
[ 590s] 区间QPS:    390382514 ops/s | 累计操作: 230217861927 | 活动块:  2048 | Page数:   2 | RSS内存: 1.96 MB

压测时间到,正在通知所有线程平滑退出并刷新 TLS...
[ 600s] 区间QPS:    389730517 ops/s | 累计操作: 234115167099 | 活动块:     0 | Page数:   2 | RSS内存: 3.89 MB

================ 最终收尾与内存泄漏验证 ================
总完成操作次数  : 234115167099
当前未归还内存块: 0
最终申请 Page 数: 2
 SUCCESS: 长跑压测通过!0 内存泄漏,0 数据损坏,性能平稳!

同等定义下

时间节点 监控输出的区间 QPS 累计总操作数 活动内存块 / Page数 RSS 物理内存 全系统总 QPS 单次 [配对+伪业务] 综合延迟
10s 389,378,654 ops/s 3,893,786,547 2048 / 2 1.96 MB 3.89 亿 ops/s 20.55 ns
100s 390,313,934 ops/s 38,985,415,079 2048 / 2 1.96 MB 3.90 亿 ops/s 20.50 ns
300s (半程) 390,827,430 ops/s 117,032,759,376 2048 / 2 1.96 MB 3.90 亿 ops/s 20.47 ns
500s 390,386,441 ops/s 195,086,159,797 2048 / 2 1.96 MB 3.90 亿 ops/s 20.49 ns
600s (终点) 389,730,517 ops/s 234,115,167,099 0 / 2 3.89 MB 3.89 亿 ops/s 20.53 ns

内存泄漏检测

Valgrind Memcheck输出如下,Asan检测无输出

两种工具的检测均没有内存泄漏

==16305== 

==16305== HEAP SUMMARY:

==16305==     in use at exit: 0 bytes in 0 blocks

==16305==   total heap usage: 1,426 allocs, 1,426 frees, 21,480,445 bytes allocated

==16305== 

==16305== All heap blocks were freed -- no leaks are possible

==16305== 

==16305== For lists of detected and suppressed errors, rerun with: -s

==16305== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

root@ecs-ec4a:~/cppMemoryPool/build#