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

UWP中AudioGraph启动后内存持续增长问题求助

解决AudioGraph启动后内存持续增长的问题

我之前在使用UWP的AudioGraph时也碰到过类似的内存泄漏问题,结合你的代码来看,核心问题是多个音频相关对象没有被正确释放,每次点击按钮都会创建新实例,旧实例却一直留在内存中。下面是具体的修复方案:

1. 清理重复创建的节点实例

每次点击按钮创建新的音频节点前,一定要先释放旧的节点资源,避免内存堆积:

针对电脑语音播放的按钮事件(BtnComputerVoice_Click)

在创建新的mediaInput和frameOutputNode前,先检查并释放旧实例:

private async void BtnComputerVoice_Click(object sender, RoutedEventArgs e)
{
    graph.Stop();
    
    // 释放旧的媒体输入节点
    if (mediaInput != null)
    {
        mediaInput.Dispose();
        mediaInput = null;
    }
    
    // 释放旧的帧输出节点
    if (frameOutputNode != null)
    {
        frameOutputNode.Dispose();
        frameOutputNode = null;
    }
    
    // 释放旧的MediaSource
    if (mediaVoice != null)
    {
        mediaVoice.Dispose();
        mediaVoice = null;
    }
    
    graph.ResetAllNodes();
    
    // 使用using自动释放SpeechSynthesizer
    using (var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer())
    {
        SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
        
        mediaVoice = MediaSource.CreateFromStream(stream, stream.ContentType);
        CreateMediaSourceAudioInputNodeResult fileInputResult = await graph.CreateMediaSourceAudioInputNodeAsync(mediaVoice);
        
        if (MediaSourceAudioInputNodeCreationStatus.Success != fileInputResult.Status)
        {
            stream.Dispose(); // 失败时也要释放流资源
            return;
        }
        
        mediaInput = fileInputResult.Node;
        mediaInput.AddOutgoingConnection(deviceOutput);
        
        frameOutputNode = graph.CreateFrameOutputNode();
        mediaInput.AddOutgoingConnection(frameOutputNode);
        frameOutputNode.OutgoingGain = 4;
        
        graph.Start();
        
        // 播放完成后自动释放流
        mediaInput.MediaSourceCompleted += (s, args) =>
        {
            stream.Dispose();
        };
    }
}

针对麦克风输入的按钮事件(BtnMicrophone_Click)

新增类成员AudioDeviceInputNode deviceInput;,然后在创建新实例前释放旧的:

// 类成员添加
AudioDeviceInputNode deviceInput;

private async void BtnMicrophone_Click(object sender, RoutedEventArgs e)
{
    if (graph != null)
    {
        graph.Stop();
        
        // 释放旧的麦克风输入节点
        if (deviceInput != null)
        {
            deviceInput.Dispose();
            deviceInput = null;
        }
        
        // 释放旧的帧输出节点
        if (frameOutputNode != null)
        {
            frameOutputNode.Dispose();
            frameOutputNode = null;
        }
        
        graph.ResetAllNodes();
    }
    
    CreateAudioDeviceInputNodeResult fileInputResult = await graph.CreateDeviceInputNodeAsync(Windows.Media.Capture.MediaCategory.Speech);
    if (AudioDeviceNodeCreationStatus.Success != fileInputResult.Status)
    {
        return;
    }
    
    deviceInput = fileInputResult.DeviceInputNode;
    frameOutputNode = graph.CreateFrameOutputNode();
    deviceInput.AddOutgoingConnection(frameOutputNode);
    
    graph.Start();
}

2. 关键注意事项

  • 使用using语句管理短期对象:比如SpeechSynthesizer这类只在方法内使用的对象,用using可以确保它在方法结束时自动释放,避免资源残留。
  • 流资源的强制释放:SpeechSynthesisStream无论创建节点成功与否,都要手动调用Dispose,它不会随MediaSource自动回收。
  • 节点事件的清理:如果给节点添加了事件监听(比如MediaSourceCompleted),若后续不再需要,记得移除监听,防止引用导致对象无法被GC回收。
  • Graph重置顺序:先手动释放所有节点资源,再调用graph.ResetAllNodes(),避免节点资源在Graph中残留。

修复后,你可以再次用Visual Studio的诊断工具观测内存变化,正常情况下播放完成或停止麦克风后,内存会逐步回落,不会持续增长。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 11:57:48