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

Rust中如何实现无内存泄漏的信号捕获

根因说明

你看到的1188字节possibly lost泄漏不是代码逻辑错误导致的可增长内存泄漏,是Tokio信号模块在Unix平台下的设计特性,不会造成程序运行期间内存持续上涨:

  • 泄漏的内存是Tokio初始化信号监听时分配的全局单例资源,包含信号管道、sigaction注册结构体、事件通知句柄,总大小固定,和程序运行时长无关
  • 这部分资源被故意设计为不在进程退出前主动释放:Unix多线程环境下注销信号处理器存在天然竞态风险,进程退出时操作系统会自动回收所有进程持有的内存、文件描述符,主动释放这部分全局资源没有实际收益,反而会引入退出阶段的崩溃风险
  • Valgrind触发possibly lost判定,是因为这部分全局资源的指针存放在静态存储区,没有被显式析构,不属于需要修复的有效泄漏,完全可以忽略。
消除Valgrind报错的可选方案

如果你必须让Valgrind的泄漏报告清零,有两个可落地的方案:

方案1:添加Valgrind抑制规则(推荐)

这是Tokio官方认可的处理方式,不需要修改业务代码,只需要过滤掉这部分已知无危害的全局资源残留即可。
新建抑制规则文件valgrind.supp,写入如下内容:

{
   tokio signal global persistent alloc
   Memcheck:Leak
   match-leak-kinds: possible
   fun:*alloc
   ...
   fun:tokio::signal::unix::registry::globals
   ...
}

运行Valgrind时追加参数--suppressions=valgrind.supp,就不会再报这部分的泄漏。

方案2:替换信号实现,手动控制资源生命周期

如果不想修改Valgrind配置,可以替换掉Tokio内置的signal::ctrl_c()接口,用支持完全析构的信号库实现监听,确保所有信号相关资源都在main退出前显式释放。
首先修改Cargo.toml依赖:

edition = "2021"
tokio = { version = "1", features = ["rt-multi-thread", "macros", "time"] }
signal-hook = "0.3"
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }

对应的业务代码修改如下:

use futures::StreamExt;
use signal_hook::consts::SIGINT;
use signal_hook_tokio::Signals;
use tokio::time::{sleep, Duration};

async fn sleep1() {
    loop {
        sleep(Duration::from_secs(1)).await;
        println!("sleep1");
    }
}

async fn sleep2() {
    loop {
        sleep(Duration::from_secs(2)).await;
        println!("sleep2");
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let s1 = Box::pin(sleep1());
    let s2 = Box::pin(sleep2());
    let mut signals = Signals::new([SIGINT])?;
    let sig = Box::pin(signals.next());

    tokio::select! {
        _ = s1 => {},
        _ = s2 => {},
        _ = sig => {},
    };
    // 显式释放信号监听实例
    drop(signals);
    println!("shutting down");
    Ok(())
}

重新编译后再用Valgrind检测,possibly lost的泄漏报告会消失。

注意事项

不要为了消除这几字节的Valgrind报告,强行修改Tokio runtime退出逻辑或者手动注销全局信号处理器,Unix信号处理的竞态很难完全覆盖,这类修改很容易引入隐蔽的生产环境崩溃问题。如果开发的是长时间运行的服务,这部分固定大小的残留完全不影响稳定性,优先选择抑制规则方案即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 20:43:10