Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Android > Admob. Утечка памяти.


Автор: asd 26.8.2014, 15:54
Простейший код. При смене ориентации экрана(любое пересоздание Activity) утекает память. Eclipse Memory Analyzer показывает что кто-то держит старый объект Activity и не даёт его освободить. Если не вызывать load, то всё нормально освобождается. 

Код

package pav.test.leaktest;

import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;

import android.os.Bundle;
import android.app.Activity;

public class MainActivity extends Activity {

    private InterstitialAd interstitial;
    int[] asd = new int [1000000];
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        interstitial = new InterstitialAd(this);
        interstitial.setAdUnitId("");        
        AdRequest adRequest = new AdRequest.Builder().build();
        interstitial.loadAd(adRequest);    // если закоментировать, то утечки не будет    
    }
}


В принципе понятно что причина в этом InterstitialAd(this); Если не вызывать load, то перекрёстная ссылка как-то обрабатывается, а если вызвать, то в  interstitial, наверное, создаётся какой-нибудь поток, который не даёт всему освободиться.

Кто сталкивался, как лечить? 

Автор: igorka 27.8.2014, 09:39
Может есть смысл убрать  private InterstitialAd interstitial; из полей класса? 
Зачем он там?


Автор: asd 27.8.2014, 10:28
Он там для последующего использования. Но даже если переместить в onCreate(просто ради теста), то ничего не изменится.

Есть вот такое решение http://stackoverflow.com/questions/24463440/android-admob-interstitial-memory-leak Однако после прочтения этой ветки(и ссылкам из неё) http://stackoverflow.com/questions/7298731/when-to-call-activity-context-or-application-context у меня сложилось впечатление, что окончательно это проблемы не решит. Во-первых не факт что использовать другой контекст безопасно, а во-вторых я так понимаю сам объект InterstitialAd будет утекать. Нужно либо найти какой-то способ заставить InterstitialAd завершить все свои операции, либо вообще выносить создание и хранение этих объектов в какой-нибудь синглтон. 

Меня больше всего смущает то, что по этой проблеме почти нет обсуждений в интернете. Не может же такого быть, чтобы такая утечка никого не волновала. Следовательно я чего-то принципиально не понимаю в том, как надо с InterstitialAd обращаться. Хотя где тут можно накосячить я понятия не имею.

Автор: Dapo 27.8.2014, 20:37
действительно интересно.. поискал решения в интернете и тоже готового решения не нашел. подумал использовать onSave(Restore)InstanceState, но ссылка на контекст делает этот метод бесполезным (кроме того надо еще и парселабл прикручивать). Может оно и не надо? Освободиться память самостоятельно когда сессия закончиться? Или там значительна утечка, что через 3-4 поворота приложение падает? Растет куча при частых поворотах? Кстати, все таки с getApplicationContext в случае с onSave(Restore)InstanceState можно попробовать костыль. 

Автор: asd 28.8.2014, 07:47
Если честно, не понял что вы предлагаете делать в onSave(Restore)InstanceState.

Утечка равна размеру класса который передаётся как контекст при создании InterstitialAd. Конкретно у меня в рабочем приложении, где я заметил этот баг, это примерно 1 метр(в основном графика). Это приводит к 2-3 падениям из-за нехватки памяти в день на 2500 сеансов(статистика Google Analytics). конкретно на моём телефоне(1 гиг памяти) падает примерно на 30 цикле пересоздания Activity.


C getApplicationContext всё работает норм. Только скорее всего сам объект InterstitialAd продолжит утекать. 

Автор: Dapo 30.8.2014, 16:35
на Save(Restore) можно попробовать такой костыль: наследуетесь от InterstitialAd с интерфейсом Parcelable. в онСэйв сохраняете его в Bundle на онРесторе восстанавливаете. Тогда ваш Ad создаваться не будет. Только не забудьте его на null проверить. Ну и это лишь непроверенная идея )

Автор: PiyodaiSiyo 1.9.2014, 00:21
может  в манифесте в активити попробовать 
Код

android:noHistory="true" 

чтоб не кэшировалось
или вообще в application
Код

android:largeHeap="true"

Автор: asd 15.9.2014, 14:00
По результатам:
Сделал так:
interstitial = new InterstitialAd(getApplicationContext());
Утечка пропадает. Падения прекратились.


Также, если у вас в коде есть 
Код

    AdListener interstitialListener = new AdListener() {
        @Override
        public void onAdClosed() {
        }        

        @Override
        public void onAdFailedToLoad(int errorCode){
        }
    };


то обработчик нужно ставить/убирать в onResume/onPause

в onResume()
interstitial.setAdListener(interstitialListener);

в onPause() 
interstitial.setAdListener(null);

Иначе память опять начинает утекать.

Автор: asd 16.9.2014, 15:42
А вот и первые последствия использования getApplicationContext() вместо this:) 

android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
at android.app.ContextImpl.startActivity(ContextImpl.java:959)
at android.content.ContextWrapper.startActivity(ContextWrapper.java:283)
at aaa.a(SourceFile:87)
at xx.q(SourceFile:624)
at yh.onTransact(SourceFile:121)
at android.os.Binder.transact(Binder.java:297)
at com.google.android.gms.internal.ac$a$a.showInterstitial(Unknown Source)
at com.google.android.gms.internal.ah.show(Unknown Source)
at com.google.android.gms.ads.InterstitialAd.show(Unknown Source)
at pav.projects.supportlibrary.GameHome.interstitialShow(GameHome.java:238)
at pav.projects.nanogramlib.NanogramHome.onFieldFull(NanogramHome.java:441)
at pav.projects.nanogramlib.GameField.onUpEvent(GameField.java:515)
at pav.projects.nanogramlib.GameField.onTouchEvent(GameField.java:536)
at android.view.View.dispatchTouchEvent(View.java:5595)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2125)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1403)
at android.app.Activity.dispatchTouchEvent(Activity.java:2369)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2073)
at android.view.View.dispatchPointerEvent(View.java:5775)
at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3141)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2650)
at android.view.ViewRootImpl.processInputEvents(ViewRootImpl.java:1017)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2659)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4514)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
at dalvik.system.NativeStart.main(Native Method)

Пока таких репортов 2.

Автор: motoklas329 26.9.2014, 10:58
Посоветуйте язык програмирование для новичка.

Автор: igorka 29.9.2014, 18:31
Цитата(motoklas329 @ 26.9.2014,  10:58)
Посоветуйте язык програмирование для новичка.

PASCAL жеж

Автор: Burka 8.10.2014, 13:07
asd, а какую версию сдк ты используешь? повторяется ли это в последней ревизии гугл сервисов?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)