Я разработал проект, который я хотел бы выпустить который использование c#, WPF и Система. Речь. Объект синтезатора. Проблема, предотвращающая выпуск этого проекта, - то, что каждый раз, когда SpeakAsync называют, он оставляет утечку памяти, которая растет на грани возможного отказа. Я полагаю, что вымылся правильно после использования этого объекта, но не могу найти средство исправления. Я запустил программу через Профилировщика Памяти Муравьев, и она сообщает, что WAVEHDR и WaveHeader растут с каждым вызовом.
Я создал демонстрационный проект попытаться точно определить причину, но все еще в недоумении. Любая справка ценилась бы.
Проект использует VS2008 и является c# WPF проект, который предназначается для.NET 3.5 и Любой ЦП. Необходимо вручную добавить ссылку на Систему. Речь.
Вот Код:
<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 и росте.
Может любой видеть что-либо в коде, который мог бы вызывать это или является этим проблема с самим Речевым объектом.
Любая справка ценилась бы.
Я могу подтвердить это наблюдение. Я рвал за волосы, пытаясь выяснить, где утекает моя программа, и это метод .SPEAK в System.speech
. Я преобразовал приложение, которое использовало объекты Speech на основе COM, для использования нового System.Speech. Net-библиотека в .Net 3.5. Звучит как правильный способ перейти к использованию всего управляемого кода в приложении .Net. В приложении внезапно произошла небольшая утечка памяти.
Я разбил это на 2 простых приложения, которые конвертируют «это тест» в WAV-файл произнесенных слов. Один использует речевые объекты на основе COM, другой - System.Speech. Я запускал их в течение 24 часов, каждый из которых создавал WAV около 200 000 раз.
Речевые объекты на основе COM: нет утечки памяти. Примерно через 40 минут объем памяти приложения достиг 13 МБ
System.speech: медленная утечка, приятная и линейная. Увеличилось с 14 до 45 МБ за 24 часа
SendAsync()
из Ping
также дает утечки. Решение состоит в том, чтобы сначала указать отправителя как IDisposable
. Так что, возможно, здесь также работает следующее.
((IDisposable)spk).Dispose();