2013-08-01 2 views
0

Привет, поэтому у меня довольно большая утечка памяти в моем приложении, и я думаю, что это вызвано моими Runnables. Вот пример скелета Runnables я использую:Will Looping Runnable Причина утечки памяти

private Runnable randomAlienFire = new Runnable() { 
     public void run() { 
      /*A Bunch 
       of computations 
      */ 

      mainHandler.removeCallbacks(randomAlienFire); 
      mainHandler.postDelayed(randomAlienFire, number); 

     } 

Когда я переключаюсь деятельность я называю mainHandler.removeCallbacksAndMessages(null); и thread.randomAlienFire = null; пока я до сих пор протекает всю активность. Поэтому мой вопрос: есть ли что-то в этом базовом скелете, вызывающем утечку памяти? Может ли это быть фактом, что обработчик призывает себя?

+0

какие вычисления вы выполняете внутри обработчика. что может вызвать утечку памяти – Raghunandan

+0

вычислений не было бы. Это можно сделать в целом интересным о – MikeT

+0

из того, что я вижу, я не вижу ничего, что вызывает утечку памяти. http://android-developers.blogspot.in/2009/01/avoiding-memory-leaks.html – Raghunandan

ответ

5

Да, ваша реализация, безусловно, вызовет утечку памяти (я просто столкнулся с этим сам).

Проблема в том, что вы создали круговую ссылку. Вы объявили свой runnable как нестатический внутренний класс, а это означает, что он автоматически сохранит ссылку на активность. Сама runnable является переменной-членом вашей активности, которая закрывает круг. Сборщик мусора никогда не сможет освободить эти объекты, так как всегда будет живая ссылка.

Использование статического внутреннего класса со слабым отношением к действию является самым безопасным способом устранения проблемы. You can see a great code example here. Если mainHandler - еще один нестатический внутренний класс, он создаст вторую круговую ссылку по тем же причинам, поэтому вам придется делать то же самое.

Установка mainHandler.removeCallbacksAndMessages(null); и thread.randomAlienFire = null; также может работать, но вы должны быть очень осторожны, когда вы помещаете этот код. Возможно, код идет по другому пути, чем вы ожидаете в некоторых случаях, и пропускаете эти вызовы? This blog post describes someone else's very similar experience with that approach.

В моем случае я использовал исполняемые анимации последовательности для ImageViews. чтобы избавиться от утечек памяти, я создал статический класс runnable, чтобы избежать циклической ссылки. Этого было недостаточно для меня, я также обнаружил, что выталкиваемый по-прежнему сохраняет ссылку на мой фрагмент. вызвав myImageView.removeCallbacksAndMessages(arrowAnimationRunnable); в onDestroy() в моем фрагменте, наконец, решила утечку. здесь было мое решение:

public class MyFragment extends SherlockFragment { 

    public static class SafeRunnable implements Runnable { 

     private final WeakReference<MyFragment> parentReference; 

     public SafeRunnable(MyFragment parent) { 
      parentReference = new WeakReference<MyFragment>(parent); 
     } 

     @Override 
     public void run() { 
      if (parentReference != null) { 
       final MyFragment parent = parentReference.get(); 
       if (parent != null) { 
        runWithParent(parent); 
       } 
      } 
     } 

     public void runWithParent(MyFragment parent) { 

     } 
    } 


    // This anonymous instance of the new runnable class does not retain a 
    reference to the fragment 
    private Runnable arrowAnimationRunnable = new SafeRunnable(this) { 

     @Override 
     public void runWithParent(MyFragment parent) { 

      // ... animation code 

      // repeat the animation in 1 second 
      parent.myImageView.postDelayed(this, 1000); 
     } 

    }; 


    private ImageView myImageView; 


    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 

     View view = inflater.inflate(R.layout.my_layout, container, false); 

     // find the image view and kick off the animation after 1 second 
     myImageView = (ImageView) view.findViewById(R.id.iv_arrow); 
     myImageView.postDelayed(arrowAnimationRunnable, 1000); 

     return view; 
    } 

    @Override 
    public void onDestroyView() { 
     super.onDestroyView(); 

     // It's necessary to remove the callbacks here, otherwise a message will 
     // be sitting in the queue and will outlive the fragment. Because a 
     // reference in that message will still be pointing to the fragment, the 
     // fragment (and everything else) will not be garbage collected 
     myImageView.removeCallbacks(arrowAnimationRunnable); 
    } 
} 
+0

этот ответ правильный? Я знаю, что есть утечка памяти, но я думаю, что Java GC теперь может обрабатывать круглые ссылки. – Charlesjean

+0

Как я вижу, у вас все еще есть утечка памяти с помощью 'arrowAnimationRunnable', потому что вы создаете нестатический анонимный класс' SafeRunnable', который содержит ссылку на родителя. Вы можете удалить 'SaveRunnable' и использовать простой' Runnable' с 'myImageView.removeCallbacks (arrowAnimationRunnable);' in' onDestroyView'. Он делает то же самое – Nexen

3

По mainHandler.postDelayed(randomAlienFire, number); вы очередями задачу, которая может иметь ссылку памяти. Но деятельность может разрушиться до фактических работ. Это вызывает утечку памяти для вас.

Чтобы избавиться от этой утечки, вы должны позвонить mainHandler.removeCallbacks(randomAlienFire); в соответствующее место, прежде чем уничтожить операцию. Например, если ваш runnable запускается из onStart(), вы должны позвонить mainHandler.removeCallbacks(randomAlienFire); в onStop();