Leaky NSSpeechSynthesizer

Posted by cwright on 2007.07.23 @ 17:34

Filed under:

NSSpeechSynthesizer, the Cocoa class responsible for giving applications a voice under OS X, is leaky. Creating and destroying thousands of instances of this class slowly consumes all the available memory in a system, leading to degrading performance and eventual application instability.

The disappointing part is that this bug was first noticed almost two years ago.

While the extent isn’t nearly as bad, it’s still not clean.

This bug came up in our Speech Synthesizer patch for Quartz Composer, featured at kineme. After much testing, profiling, and refactoring, a splendidly small demonstration program emerged.

#import <Cocoa/Cocoa.h>;
 
int main()
{
        while(1)
        {
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
                NSSpeechSynthesizer *speech = [[NSSpeechSynthesizer alloc] init];
                [speech release];
                [pool release];
        }
 
        return 0;
}

This program endlessly allocates an NSAutoreleasePool, used for memory management, and then an NSSpeechSynthesizer object. After creating them, it destroys them. Destroying the synthesizer object should free any associated memory with the object, and releasing the pool should free up any odds and ends left over, just in case.

Reality paints a much more disappointing picture:

cwright@phendrana:~/projects/SpeechTest>./rapid 
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Segmentation fault

It starts off looking ok. It spins for about 15 seconds or so, but then trouble strikes. As you an see, the class starts to have difficulty mapping a voice file (this is only mentioned once in all of Google’s wisdom, with no useful insight as to what it means), and eventually the inevitable crash occurs.

smokris tried this on his MacBook Pro.. Same thing there:

smokris@etu 6 ~/Desktop -> time ./a.out
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Speech Synthesis can't map voice file (12)
Segmentation fault
 
real    0m4.479s
user    0m0.286s
sys     0m0.153s

This was fixed in Mac OS X 10.5 (Leopard) – yay!