Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TextToSpeech and memory leak

I've been having app crashes due to an out-of-memory condition (in the program, not the programmer). MAT shows that copies of my Activity were sometimes being retained across screen rotations, and the only object keeping the bogus copies alive was each instance's TextToSpeech object. I can duplicate this behaviour using this snippet:

public class MainActivity extends Activity {
    TextToSpeech    mTts;
    char[]          mBigChunk = new char[1000000];  // not used; just makes MainActivity instances easier to see in MAT

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public void onStart() {
        super.onStart();
        if (mTts==null)                             // shouldn't be necessary and doesn't make any difference
            mTts = new TextToSpeech(this, null);        // commenting this out fixes the leak
    }
    @Override
    public void onStop() {
        super.onStop();
        if (mTts != null) {
            mTts.shutdown();
            mTts = null;        // shouldn't be necessary and doesn't make any difference
        }
    }
}

After 30 orientation changes, MAT lists between one and eight instances of net.catplace.tts_leak.MainActivity, and also multiple instance of various TTS objects; eg:

Class Name                                                            | Shallow Heap | Retained Heap | Percentage
------------------------------------------------------------------------------------------------------------------
android.speech.*                                                      |              |               |           
android.speech.tts.TextToSpeech$Connection$1 @ 0x42de94c8 Native Stack|           24 |     2,052,664 |     11.85%
android.speech.tts.TextToSpeech$Connection$1 @ 0x431dd500 Native Stack|           24 |     2,052,664 |     11.85%
android.speech.tts.TextToSpeech$Connection$1 @ 0x435cc438 Native Stack|           24 |           552 |      0.00%
android.speech.tts.TextToSpeech$Connection @ 0x441b3698               |           32 |           528 |      0.00%
android.speech.tts.TextToSpeech @ 0x43fb3c00                          |           64 |           496 |      0.00%
android.speech.tts.TextToSpeech$Connection @ 0x43fb4420               |           32 |            48 |      0.00%
android.speech.tts.TextToSpeech$Connection$1 @ 0x43fb4440 Native Stack|           24 |            24 |      0.00%
android.speech.tts.TextToSpeech$Connection$1 @ 0x441b36b8 Native Stack|           24 |            24 |      0.00%
Total: 8 entries (13,079 filtered)                                    |              |               |           
------------------------------------------------------------------------------------------------------------------

MAT indicates that the bogus copies of MainActivity are being retained by TTS:

Class Name                                                                            | Shallow Heap | Retained Heap
---------------------------------------------------------------------------------------------------------------------
                                                                                      |              |              
net.catplace.tts_leak.MainActivity @ 0x437c6068                                       |          200 |     2,001,352
'- mContext android.speech.tts.TextToSpeech @ 0x431de6d8                              |           64 |           496
   '- this$0 android.speech.tts.TextToSpeech$Connection @ 0x441b3698                  |           32 |           528
      '- this$1 android.speech.tts.TextToSpeech$Connection$1 @ 0x441b36b8 Native Stack|           24 |            24
---------------------------------------------------------------------------------------------------------------------

I get this behavour across a range of real devices and AVDs. The above results are from a Nexus 7.

I've tried different TTS engines, using different events to create and destroy mTts, etc.

My hypothesis is that TextToSpeech doesn't always null its reference to the context that created it, resulting in leaked copies of the context (Activity). But I'm new at this; is there something I'm doing wrong?

like image 946
Peter McLennan Avatar asked Oct 29 '13 08:10

Peter McLennan


1 Answers

Taking a look at the source code of TextToSpeech here, you'll notice that it actually binds a service to the context passed and the shutdown method actually unbinds it. Now rest ahead is guess, since Service has its own life cycle,the TextToSpeech might be holding back the context.If you did some research keeping this in mind that you're actually running a service,you might crack the question.

Now I'm not also sure what this might imply but I am open for any new findings from your side. Given that TextToSpeech is a service you might want to pass it the application context, since the service would still be running when activity gets destroyed.

Also for further reading ______________

like image 108
Parvaz Bhaskar Avatar answered Nov 01 '22 09:11

Parvaz Bhaskar