TextToSpeech和内存泄漏

时间:2013-10-29 08:33:36

标签: android memory-leaks text-to-speech google-text-to-speech

由于内存不足(在程序中,而不是程序员),我一直在进行应用程序崩溃。 MAT显示我的Activity的副本有时会在屏幕旋转中保留,而保持虚假副本的唯一对象是每个实例的TextToSpeech对象。我可以使用此代码段复制此行为:

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
        }
    }
}

在30个方向更改后,MAT列出了net.catplace.tts_leak.MainActivity的一到八个实例,以及各种TTS对象的多个实例;例如:

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表示TTS保留了MainActivity的伪造副本:

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
---------------------------------------------------------------------------------------------------------------------

我在一系列真实设备和AVD中获得了这种行为。以上结果来自Nexus 7。

我尝试过不同的TTS引擎,使用不同的事件来创建和销毁mTts等。

我的假设是TextToSpeech并不总是将其对创建它的上下文的引用置空,从而导致上下文的泄露副本(Activity)。但我是新来的;有什么我做错了吗?

2 个答案:

答案 0 :(得分:1)

看一下TextToSpeech here的源代码,您会注意到它实际上将服务绑定到传递的上下文,而shutdown方法实际上将其解除绑定。现在休息是猜测,因为Service有自己的生命周期,TextToSpeech可能会阻碍上下文。如果你做了一些研究,记住你实际上正在运行一个服务,你可能会破解这个问题。

现在我不确定这可能意味着什么,但我愿意接受你身边的任何新发现。 鉴于TextToSpeech是一项服务,您可能希望将其传递给应用程序上下文,因为当活动被销毁时服务仍将运行。

Also for further reading ______________

答案 1 :(得分:0)

如果没有实施android:configChanges="orientation",那么您可以覆盖onDestory方法:

@Override
protected void onDestroy() {
    super.onDestroy();
    if (ttsEngine != null) {
        ttsEngine.stop();
        ttsEngine.shutdown();
        Log.d(TAG, "TTS destroyed");
    }
}