8

c#、WPF、および System.Speech.Synthesizer オブジェクトを使用する、リリースしたいプロジェクトを開発しました。このプロジェクトのリリースを妨げている問題は、SpeakAsync が呼び出されるたびにメモリ リークが発生し、最終的には失敗に至ることです。このオブジェクトを使用した後、適切にクリーンアップしたと思いますが、治療法が見つかりません。Ants Memory Profiler を使用してプログラムを実行したところ、呼び出しごとに WAVEHDR と WaveHeader が増加していることが報告されました。

原因を特定するためにサンプルプロジェクトを作成しましたが、まだ途方に暮れています。どんな助けでも大歓迎です。

このプロジェクトは VS2008 を使用し、.NET 3.5 および任意の CPU をターゲットとする ac# 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 オブジェクト自体の問題ですか?

どんな助けでも大歓迎です。

4

4 に答える 4

5

これは Speak メソッドの既知の問題です。SPVTEXTFRAG という構造が作成され、破棄されることはありません。

詳細はこちら: http://connect.microsoft.com/VisualStudio/feedback/details/664196/system-speech-has-a-memory-leak

于 2011-09-17T19:41:22.720 に答える
3

この観察結果を確認できます。私は自分のプログラムがどこに漏れているのかを突き止めようとして髪を引っ張っていました。それはSystem.speechの.SPEAKメソッドです。

COMベースのSpeechオブジェクトを使用するアプリを、.Net3.5の新しいSystem.Speech.Netライブラリを使用するように変換しました。.Netアプリ内ですべての管理されたコードを使用するために前進する正しい方法のように聞こえました。アプリで突然小さなメモリリークが発生しました。

私はこれを2つの簡単なアプリに分解し、「これはテストです」を話し言葉のWAVファイルに変換します。1つはCOMベースの音声オブジェクトを使用し、もう1つはSystem.Speechを使用します。私はそれらを24時間実行し、それぞれが約200,000回WAVを作成しました。

COMベースの音声オブジェクト:memリークはありません。アプリのメモリ使用量は、約40分後に13MBでピークに達しました

System.speech:リークが遅く、素晴らしく直線的です。24時間で約14MBから45MBになりました

于 2010-03-14T12:56:25.710 に答える
2

SendAsync()からPingも漏れます。IDisposable解決策は、送信者を最初にキャストすることです。したがって、以下もここで機能する可能性があります。

((IDisposable)spk).Dispose();
于 2010-08-26T01:26:51.060 に答える
0

あなたの質問に対して本当に簡単な答えを出すことができます: SpeechSynthesizer を静的にします!!!

これで問題が解決すると確信しています。

また - ヒント ==>> コードを作成するたびに、リソースを持っています...それを静的として使用すると、あなたの人生はより良くなります!

于 2012-02-15T19:07:38.893 に答える