2017-01-16 3 views
1

Согласно Romain Guy такого рода код подвержен утечке памяти из-за того, чтоПочему ссылка на Контекст на утечку памяти?

.... взгляды имеют ссылку на всю деятельность и, следовательно, к чему ваша деятельность держит на; как правило, всю иерархию View и все ее ресурсы.

@Override 
protected void onCreate(Bundle state) { 
    super.onCreate(state); 

    TextView label = new TextView(this); 
    label.setText("Leaks are bad"); 

    setContentView(label); 
} 

Я не ясно об этом.
Предполагая, что приложение имеет 1 активность, это самый длинный объект и может быть воссоздан по мере необходимости. Это означает, что все его поля экземпляров (которые могут и обычно равны View) могут быть нулевыми в любое время.
И любое статическое поле экземпляра будет жить в течение той же продолжительности, что и сама деятельность.
Так как мы можем получить утечку памяти с кодом, как выше или следующее:

private static Drawable sBackground; 

@Override 
protected void onCreate(Bundle state) { 
    super.onCreate(state); 

    TextView label = new TextView(this); 
    label.setText("Leaks are bad"); 

    if (sBackground == null) { 
    sBackground = getDrawable(R.drawable.large_bitmap); 
    } 
    label.setBackgroundDrawable(sBackground); 

    setContentView(label); 
} 

ответ

7

Предполагая, что приложение с 1 активности, это самый длинный жил объект

Нет, не является. В вашем процессе есть другие объекты (например, Application, поставщики контента), которые оживят экземпляр действия.

В частности, обратите внимание, что действия будут уничтожены и воссозданы по умолчанию при изменении конфигурации (например, при вращении экрана).

И любое статическое поле экземпляра будет жить в течение той же продолжительности, что и сама деятельность.

Нет. Статические поля вокруг тех пор, пока процесс вокруг. Экземпляры вашей деятельности могут быть более короткими, чем это.

Так как мы можем получить утечку памяти с кодом, как выше или следующее:

Там нет статического поля в первом примере.

Romain Guy объясняет второй сценарий в the blog post that you linked to:

Этот код очень быстро и очень неправильно; он теряет первую активность, созданную при первом изменении ориентации экрана. Когда Drawable прикреплен к представлению, представление задается как обратный вызов на drawable. В фрагменте кода выше, это означает, что рисуем имеет ссылку на TextView, которая сама имеет ссылку на деятельности (Context), который в свою очередь имеет ссылки на почти все, что (в зависимости от вашего кода.)

И, если вы добавите LeakCanary в свой проект, вы увидите утечку.

Итак, давайте пройдем через это:

  • Пользователь вводит на панели запуска главного экрана для вашего приложения, который связан с этой деятельностью
  • Ваш процесс начался
  • Ваш экземпляр деятельности создается , а затем вызывается с onCreate()
  • sBackground является null, и таким образом присвоить ему getDrawable() результат
  • на экране
  • The чихает пользователя и случайно появляется Ваша деятельность UI поворачивает экран устройства в части реагирования на чих
  • Ваш старый экземпляр деятельности уничтожен
  • новый экземпляр деятельности создается, и затем вызывается с onCreate()
  • sBackgroundне null, и поэтому вы оставить в покое sBackground

и у вас есть утечка. Как объяснил Ромен, sBackground имеет не очень очевидную ссылку на ваш оригинал экземпляр деятельности. Итак, теперь у вас есть два выдающихся экземпляра этого действия: просочившийся оригинал, а также новый, созданный из-за изменения конфигурации.

+0

Итак, у первого фрагмента нет утечки памяти? – Jim

+0

@Jim: Правильно. Я предполагаю, что он должен проиллюстрировать предложение, непосредственно предшествующее фрагменту кода («Обычно это первый, который разработчик передает классам и методам, которым нужен контекст:»), показывая передачу «Контекста» в «TextView» конструктор. – CommonsWare

Смежные вопросы