【发布时间】:2011-01-13 07:47:49
【问题描述】:
我开发了一个我想发布的项目,它使用 c#、WPF 和 System.Speech.Synthesizer 对象。阻止该项目发布的问题是,每当调用 SpeakAsync 时,它都会留下内存泄漏,并最终导致失败。我相信我在使用此物品后已正确清理,但找不到治疗方法。我已经通过 Ants Memory Profiler 运行了该程序,它报告 WAVEHDR 和 WaveHeader 在每次调用时都在增长。
我创建了一个示例项目来尝试查明原因,但仍然不知所措。任何帮助将不胜感激。
该项目使用 VS2008,是一个针对 .NET 3.5 和 Any CPU 的 c# WPF 项目。您需要手动添加对 System.Speech 的引用。
代码如下:
<Window x:Class="SpeechTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel Orientation="Vertical">
<Button Content="Start Speaking" Click="Start_Click" Margin="10" />
<Button Content="Stop Speaking" Click="Stop_Click" Margin="10" />
<Button Content="Exit" Click="Exit_Click" Margin="10"/>
</StackPanel>
</Grid>
// Start of code behind
using System;
using System.Windows;
using System.Speech.Synthesis;
namespace SpeechTest
{
public partial class Window1 : Window
{
// speak setting
private bool speakingOn = false;
private int curLine = 0;
private string [] speakLines = {
"I am wondering",
"Why whenever Speech is called",
"A memory leak occurs",
"If you run this long enough",
"It will eventually crash",
"Any help would be appreciated" };
public Window1()
{
InitializeComponent();
}
private void Start_Click(object sender, RoutedEventArgs e)
{
speakingOn = true;
SpeakLine();
}
private void Stop_Click(object sender, RoutedEventArgs e)
{
speakingOn = false;
}
private void Exit_Click(object sender, RoutedEventArgs e)
{
App.Current.Shutdown();
}
private void SpeakLine()
{
if (speakingOn)
{
// Create our speak object
SpeechSynthesizer spk = new SpeechSynthesizer();
spk.SpeakCompleted += new EventHandler(spk_Completed);
// Speak the line
spk.SpeakAsync(speakLines[curLine]);
}
}
public void spk_Completed(object sender, SpeakCompletedEventArgs e)
{
if (sender is SpeechSynthesizer)
{
// get access to our Speech object
SpeechSynthesizer spk = (SpeechSynthesizer)sender;
// Clean up after speaking (thinking the event handler is causing the memory leak)
spk.SpeakCompleted -= new EventHandler(spk_Completed);
// Dispose the speech object
spk.Dispose();
// bump it
curLine++;
// check validity
if (curLine >= speakLines.Length)
{
// back to the beginning
curLine = 0;
}
// Speak line
SpeakLine();
}
}
}
}
我在 Windows 7 64 位上运行此程序,它会在尝试创建新的 SpeechSynthesizer 对象时运行并最终停止。在 Windows Vista 64 位上运行时,内存将从起点的 34k 增长到目前的大约 400k 并且还在增长。
任何人都可以在代码中看到任何可能导致此问题的内容,或者这是 Speech 对象本身的问题。
任何帮助将不胜感激。
【问题讨论】:
-
你确定它一直在上升吗? .net 中的内存将继续增加,直到 GC 通过并清理所有内容。除非它持续上升并且从不下降,否则我不会担心它。
-
是的,当我在 Windows 7 上运行它时,它最终会在尝试创建新的 SpeechSynthesizer 对象时停止。程序停止后,转到控制面板并尝试测试文本转语音将得到相同的结果。在机器重新启动之前它不会再说话。
-
如果您不在每次传递中创建新的 SpeechSynthesizer 对象会发生什么?
-
Eric,我第一次尝试过这种方式,但实际上更糟。这就是我尝试在每次调用时创建和销毁对象的原因。它确实略有改善,但仍然没有解决问题。任何对 SpeechSynthesizer 的调用都会留下 WAVEHDR 和 WaveHeader 对象,这些对象会增加私有内存直到崩溃。
-
在不同的
AppDomain中调用语音是否有帮助,然后定期卸载该域,它会回收内存吗?
标签: c# wpf memory-leaks text-to-speech