none
Memory Leak with SpeechSynthesizer -- Please HELP RRS feed

  • Question

  • I have developed a project which I would like to release which uses c#, WPF and the System.Speech.Synthesizer object. The issue preventing the release of this project is that whenever SpeakAsync is called it leaves a memory leak that grows to the point of eventual failure. I believe I have cleaned up properly after using this object, but cannot find a cure.

    I have run the program through Ants Memory Profiler and it reports that WAVEHDR and WaveHeader is growing with each call.

    I have created a sample project to try to pinpoint the cause, but am still at a loss. Any help would be appreciated.

    The project uses VS2008 and is a c# WPF project that targets .NET 3.5 and Any CPU. You need to manually add a reference to System.Speech.

    Here is the simple Code:

    <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>
    </Window>
    Here is the code behind.

    // 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<SpeakCompletedEventArgs>(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<SpeakCompletedEventArgs>(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();
                }
            }
        }
    }

    I run this program on Windows 7 64 bit and it will run and eventually halt when attempting to create a new SpeechSynthesizer object. When run on Windows Vista 64 bit the memory will grow from a starting point of 34k to so far about 400k and still growing.

    Once the program fails on Windows 7, attempting to test the speech from the Control panel also fails.  It will no longer speak until the machine is restarted.

    Can anyone see anything in the code that might be causing this, or is this an issue with the Speech object itself.

    Any help would be appreciated.

    • Moved by Jay_WangMicrosoft employee Friday, February 12, 2010 3:58 AM The speech API doesn't belong to WPF, although you're working on a WPF project, this specific problem has nothing to do with WPF technology. (From:Windows Presentation Foundation (WPF))
    Friday, February 5, 2010 12:47 AM

All replies

  • Seriously??  Nobody has any idea what is happening with this? 

    This issue makes using the System.Speech unusable in any project.
    Sunday, February 7, 2010 12:40 AM
  • Hi DudeFX,

    perhaps you could create the speech object once and just reuse it rather than create and destroy it for each line of text.

    i know this is just a general solution, but if there is a bug in the dispose of the object, then at least you wont have to bang your head against the problem.

    Cheers
    Anton



    Sunday, February 7, 2010 1:48 AM
  • That is a smart suggestion, Anton.  Unfortunately this was the way I tried it the first time through as I have no reason to create and destroy the SpeechSynthesizer object.

    using System;
    using System.Windows;
    using System.Speech.Synthesis;
    
    namespace SpeechTest
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
    
            // speak setting
            private SpeechSynthesizer spk = new SpeechSynthesizer();
            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()
            {
                spk.SpeakCompleted += new EventHandler<SpeakCompletedEventArgs>(spk_Completed);
                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)
                {
                    // Speak the line
                    spk.SpeakAsync(speakLines[curLine]);
                }
            }
    
            public void spk_Completed(object sender, SpeakCompletedEventArgs e)
            {
                if (sender is SpeechSynthesizer)
                {
     
                    // bump it
                    curLine++;
                    // check validity
                    if (curLine >= speakLines.Length)
                    {
                        // back to the beginning
                        curLine = 0;
                    }
                    // Speak line
                    SpeakLine();
                }
            }
        }
    }
    Unfortunately, (I believe) it is SpeakAsync which leaves several WAVEHDR and WaveHeader objects in memory with each call.  The number simply grows and grows but never get cleaned up.

    Any other ideas?
    Sunday, February 7, 2010 4:34 AM