I found a continuous leakage in my application. After examining using a memory profiler, I found the course is some object from Microsoft Speech.Synthesizer
So I build up a toy project to verify the hypothesis:
//Toy example to show memory leak in Speech.Synthesizer object
static void Main(string[] args)
{
string text = "hello world. This is a long sentence";
PromptBuilder pb = new PromptBuilder();
pb.StartStyle(new PromptStyle(PromptRate.ExtraFast));
pb.AppendText(text);
pb.EndStyle();
SpeechSynthesizer tts = new SpeechSynthesizer();
while (true)
{
//SpeechSynthesizer tts = new SpeechSynthesizer();
Console.WriteLine("Speaking...");
tts.Speak(pb);
//Print private working set sieze
Console.WriteLine("Memory: {0} KB\n", (Process.GetCurrentProcess().PrivateMemorySize64 / 1024).ToString("0"));
//tts.Dispose(); //also this doesn't work as well
//tts = null;
GC.Collect(); //a little help, but still leaks
}
}
And the result actually confirmed the memory leak is from Speech.Synthesizer
Speaking...
Memory: 42184 KB
Speaking... Memory: 42312 KB
Speaking... Memory: 42440 KB
Speaking... Memory: 42568 KB
Speaking... Memory: 42696 KB
Speaking... Memory: 42824 KB
Speaking... Memory: 43016 KB
Speaking... Memory: 43372 KB
I googled it and found many others have come across the same problem: 1: Constant Memory Leak in SpeechSynthesizer 2: http://connect.microsoft.com/VisualStudio/feedback/details/664196/system-speech-has-a-memory-leak
but sadly I didn't find any solution to it. Since its a problem already asked long time ago, so I want to ask if its been solved or not?
Many Thanks.
UPDATE:
Seems like while I switch to use SAPI COM dll rather than .Net Speech.Synthesizer package (although essentially they are the same thing), the memory stops leaking.
Why is the two invoke behavior (SAPI dll vs .net Speech package) have different memory behavior? As the latter seems is just a wrapper to the former SAPI dll.
static void Test2()
{
//SAPI COM component this time
SpeechLib.SpVoiceClass tts = new SpeechLib.SpVoiceClass();
tts.SetRate(5);
string text = "hello world. This is a long sentence";
//tts.Speak("helloWorld", SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
while (true)
{
Console.WriteLine("Speaking...");
tts.Speak(text, SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
//Print private working set sieze
Console.WriteLine("Memory: {0} KB\n", (Process.GetCurrentProcess().PrivateMemorySize64 / 1024).ToString("0"));
GC.Collect();
}
}
Memory: 32044 KB
Speaking... Memory: 32044 KB
Speaking... Memory: 32044 KB
Speaking... Memory: 32044 KB
Speaking... Memory: 32044 KB
Speaking... Memory: 32044 KB
Speaking... Memory: 32044 KB
Speaking... Memory: 32044 KB
A memory leak may happen when your app references objects that it no longer needs to perform the desired task. Referencing said objects makes the garbage collector to be unable to reclaim the memory used, often resulting in performance degradation and potentially end up throwing an OutOfMemoryException.
If you have implemented a very long-running or infinite running thread that is not doing anything and it holds on to objects, you can cause a memory leak as these objects will never be collected. The fix for this is to be very careful with long-running threads and not hold on to objects not needed.
A memory leak reduces the performance of the computer by reducing the amount of available memory. Eventually, in the worst case, too much of the available memory may become allocated and all or part of the system or device stops working correctly, the application fails, or the system slows down vastly due to thrashing.
Final solution:
Google-ing relevant keywords telling me that it's actually a bug from Microsoft.
Seems like while I switch to use SAPI COM dll rather than .Net Speech.Synthesizer package (although essentially they are the same thing), the memory stops leaking.
I'm not sure all the details on the SpeechSynthesizer, but you could try using the disposable pattern here. Since SpeechSynthesizer implements IDisposable
Your code would look like the following:
while (true)
{
using (SpeechSynthesizer tts = new SpeechSynthesizer())
{
Console.WriteLine("Speaking...");
tts.Speak(pb);
//Print private working set sieze
Console.WriteLine("Memory: {0} KB\n",(Process.GetCurrentProcess().PrivateMemorySize64 / 1024).ToString("0"));
}
}
If you notice this is very similar to Microsoft's example Here
This looks to in fact be a memory leak, Have you tried using the Microsoft.Speech runtime? The syntax looks very similar and they have mentioned it shouldn't have the same issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With