Обычная версия
Java форум JavaTalks
форум программистов

Поиск   Пользователи   Группы   Регистрация 
 Профиль   Личные сообщения 

 Вход 

Inner classes && Static inner classes
Список форумов
 ->  Разное


На страницу Пред.  1, 2 
Начать новую тему 
Предыдущая тема :: Следующая тема  
Автор Сообщение
OneHalf : 103
Новичок

СообщениеИюн 22, 2011 22:06 
Ответить с цитатой
Какая разница, что ставить слушателем: внутренний класс или внешний объект?
Если в качестве слушателя поставить внешний класс, реализующий ActionListener, то сборщик мусора точно также ничего не соберет, ведь ссылка на внешний класс все равно существует! Просто тогда существует она не во внутреннем анонимном классе, а в объекте, в котором регистрируются слушатели. Т.е. тут ничего принципиально не меняется - хотите чтобы внешний класс уничтожился сборщиком - удаляйте слушателей.

Хотя, возможно, вы имеете ввиду случай, когда слушателю не нужен доступ к переменным внешнего класса. Тогда действительно имеет смысл использовать статические вложенные классы, или вообще делать их не внутренними, а вполне самостоятельными.
К началу Посмотреть профиль Отправить личное сообщение
XoJIoD : 459
Бывалый

СообщениеИюн 22, 2011 22:21 
Ответить с цитатой
Если мы добавим в слушатели экземпляр внешнего класса, в котором нет ссылки на объект, его создающий (например, с пустой реализацией actionPerformed, как в примере), то ссылка на объект, создающий ActionListener'a ниоткуда сама по себе не появится, соответственно утечки не будет

UPD: прошу прощения, не дочитал Ваш пост, вы говорили о том же
К началу Посмотреть профиль Отправить личное сообщение
sgdread : 2184
JT Библиотекарь
Откуда: USA

СообщениеИюн 23, 2011 2:06 
Ответить с цитатой
Так, беседа заходит в тупик. Вот вам код с утечкой памяти, вызванной применением анонимных и не-статических внутренних классов.
Код:
public interface Result {}


Код:
public class OuterClass {
   int[] data = null;

   public OuterClass(int s) {
      data = new int[s];
   }

   public Result getResult() {
      return new Result() { // <-- Утечка Outer класса со всеми потрохами наружу!!!
      };
   }
}


Запускаем хозяйство выше следующим кодом:
Код:
   public static void main(String[] args) {
      List<Result> l = new ArrayList<Result>();
      int i = 0;
      while (true) {
         l.add(new OuterClass(10000).getResult());
         if (i % 10000 == 0) {
            System.out.println(i);
         }
         i++;
      }
   }

У меня валится в OutOfMemoryError на 40000+. Чтобы показать, что проблема не в GC, просто сделаем имплементацию КОНКРЕТНОГО класса (только в отдельном файлике или в статическом Inner-класе плиз, а то нестатические имеют ту же проблему, что и анонимные):
Код:
class ResultImpl implements Result {}

и модифицируем OuterClass:
Код:
public class OuterClass {
   int[] data = null;

   public OuterClass(int s) {
      data = new int[s];
   }

   public Result getResult() {
      return new ResultImpl(); // <- нет утечек!!!
   }
}

Во втором случае мы видим, что приложение жизнерадостно бегает, периодически стопорясь на массивные сборки GC.
Я почему про Swing завел разговор, потому как это довольно распространенная утечка. Конкретных примеров не дам, т. к. нету под рукой, а писать лень.
Эти грабли особенно актуальны на платформах с ограниченной памятью: к примеру на Android.
_________________
К началу Посмотреть профиль Отправить личное сообщение
Skipy : 4801
Я тут живу!
Откуда: Москва, Россия

СообщениеИюн 23, 2011 8:44 
Ответить с цитатой
sgdread писал(а):
Ну вы бы почитали сначала, что я написал. Даже если вы уберете слушатели через removeListener, утечка останется. Причина не в добавлении/удалении, а в том, что анонимный inner-класс неявно содержит ссылку на объект-родитель (возьмите декомпилируйте код с inner-классом и увидите своими глазами - в анонимный класс передается this объекта-родителя). В результате, если у вас есть кнопочка, которая создает новое модальное окно, слушатель на которой - анонимный класс, вы получити феерическую утечку памяти - все модальные окна, созданные таким ActionListener-ом будут храниться в памяти и не будут собраны, пока не будет собран компонент с кнопочкой. Проблема ИМЕННО в анонимных inner-классах.


Я почитал, и внимательно. Только вот вопрос - нафига в модальном окне ставить слушателя на кнопку в основном фрейме?

Если слушатель на кнопке в модальном окне - весь граф будет убран сборщиком. Если Вы прилагаете усилия, чтобы прикопать ссылку на анонимный класс, который, в свою очередь, держит модальное окно, - ну, извините, Вы сами себе злобный Буратино.

В общем, моё резюме. Проблема не в нестатических иннер-классах как таковых, а в непонимании принципов их устройства и, соответственно, в некорректном их использовании.

P.S. Кстати, я не понял вот этого:

Цитата:
В результате, если у вас есть кнопочка, которая создает новое модальное окно, слушатель на которой - анонимный класс, вы получите феерическую утечку памяти - все модальные окна, созданные таким ActionListener-ом будут храниться в памяти и не будут собраны, пока не будет собран компонент с кнопочкой. Проблема ИМЕННО в анонимных inner-классах.


Где будет храниться твердая ссылка на созданное модальное окно, если его экземпляр создается в методе и, соответственно, память под ссылку на него выделяется только на фрейме вызова и исключительно на время работы метода?
_________________
С уважением,
Евгений aka Skipy
www.skipy.ru
P.S. Я НЕ решаю задачи ЗА других!
К началу Посмотреть профиль Отправить личное сообщение Посетить сайт автора
sgdread : 2184
JT Библиотекарь
Откуда: USA

СообщениеИюн 23, 2011 19:09 
Ответить с цитатой
Skipy писал(а):
В общем, моё резюме. Проблема не в нестатических иннер-классах как таковых, а в непонимании принципов их устройства и, соответственно, в некорректном их использовании.

Верно! И наше обсуждение прямо подтверждает этот факт. Пример утечки см. выше.
_________________
К началу Посмотреть профиль Отправить личное сообщение
initmax : 165
Новичок
Откуда: Moon

СообщениеИюн 24, 2011 8:52 
Ответить с цитатой
Vermut писал(а):
sgdread писал(а):
В результате, если у вас есть кнопочка, которая создает новое модальное окно, слушатель на которой - анонимный класс, вы получити феерическую утечку памяти - все модальные окна, созданные таким ActionListener-ом будут храниться в памяти и не будут собраны, пока не будет собран компонент с кнопочкой. Проблема ИМЕННО в анонимных inner-классах.

Что помешает собирать сборщику мусора создаваемые в листенере окна, ведь он же запоминает ссылку не на них, а на родительский объект?


Дело в том что инер класс хоть и инер но всё же класс, и он содержит линк на объект в который вложен. GC учищает только те объекты на которых нет ни одной ссылки, вот и происходит засорение кучи.
_________________
Пишу дипломы, курсовые, лабары. Консультирую по скайпу до полного прозрения. Обращайтесь в личку.
К началу Посмотреть профиль Отправить личное сообщение
Vermut : 1062
Завсегдатай
Откуда: Ростов-на-Дону

СообщениеИюн 24, 2011 19:58 
Ответить с цитатой
Спасибо кэп. Только вопрос был про то, что помешает собирать объекты на которые листенер не хранит ссылки, а только является инициатором их порождения.
_________________
Познакомлюсь с привлекательной Ростовчанкой для совместного изучения Java
К началу Посмотреть профиль Отправить личное сообщение Отправить e-mail
stolzen : 422
Бывалый
Откуда: Нижний Новгород

СообщениеИюн 25, 2011 12:34 
Ответить с цитатой
Так значит все-таки как нужно правильно реализовывать ActionListener классы?

Код:
public class SomeClass {
    static public void main(String[] args) {
        JButton b = new JButton();
       
        // первый вариант
        b.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Some Action");
            }
        });
       
        // второй вариант
        b.addActionListener(new AL());
       
        b.doClick();
    }
   
    // второй вариант
    static class AL implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Another Action");
        }
    }
}


Вторым вариантом что ли?
К началу Посмотреть профиль Отправить личное сообщение Посетить сайт автора
OneHalf : 103
Новичок

СообщениеИюн 25, 2011 12:52 
Ответить с цитатой
Кстати, а анонимный класс, созданный из static метода, случайно не является статическим?

Upd: Является. Значит оба варианта в посте выше эквивалентны.
Но в общем ответ прост: если не требуется доступ к нестатическим полям и методам внешнего класса - используйте статические, требуется - нестатические.
Статичность анонимных классов определяется блоками, в которых они объявлены
К началу Посмотреть профиль Отправить личное сообщение
Bandito2000 : 7
Новичок

СообщениеАвг 09, 2011 12:44 
Ответить с цитатой
sgdread писал(а):
Так, беседа заходит в тупик. Вот вам код с утечкой памяти, вызванной применением анонимных и не-статических внутренних классов.
Код:
public interface Result {}


Код:
public class OuterClass {
   int[] data = null;

   public OuterClass(int s) {
      data = new int[s];
   }

   public Result getResult() {
      return new Result() { // <-- Утечка Outer класса со всеми потрохами наружу!!!
      };
   }
}


Запускаем хозяйство выше следующим кодом:
Код:
   public static void main(String[] args) {
      List<Result> l = new ArrayList<Result>();
      int i = 0;
      while (true) {
         l.add(new OuterClass(10000).getResult());
         if (i % 10000 == 0) {
            System.out.println(i);
         }
         i++;
      }
   }

У меня валится в OutOfMemoryError на 40000+. Чтобы показать, что проблема не в GC, просто сделаем имплементацию КОНКРЕТНОГО класса (только в отдельном файлике или в статическом Inner-класе плиз, а то нестатические имеют ту же проблему, что и анонимные):
Код:
class ResultImpl implements Result {}

и модифицируем OuterClass:
Код:
public class OuterClass {
   int[] data = null;

   public OuterClass(int s) {
      data = new int[s];
   }

   public Result getResult() {
      return new ResultImpl(); // <- нет утечек!!!
   }
}

Во втором случае мы видим, что приложение жизнерадостно бегает, периодически стопорясь на массивные сборки GC.
Я почему про Swing завел разговор, потому как это довольно распространенная утечка. Конкретных примеров не дам, т. к. нету под рукой, а писать лень.
Эти грабли особенно актуальны на платформах с ограниченной памятью: к примеру на Android.


Всем привет.
Не знаю может эта тема уже никому не интересна, но я всё же напишу своё мнение насчёт этого примера.
В даном примере, так называемая утечка памяти будет и в первом и во втором случае. Просто в первом случае у нас метод getResult создаёт и возвращает сыллку на объёкт (экземпляр) анонимного класса, который реализует итерфейс Result. Во втором случае метод getResult создаёт объект не анонимного класса ResultImpl, который реализует итерфейс Result. Я хочу сказать что и в первом и втором случае метод getResult создаёт в памяти новый объект и возвращает ссылку на него, которая в свою очередь записывается в List (l). И соответсвенно пока у нас будут ссылки на эти объекты в листе то никакой GC не будет их удалять из памяти.
Считаю данный пример не коректным. Если я не прав поправьте меня.
К началу Посмотреть профиль Отправить личное сообщение
XoJIoD : 459
Бывалый

СообщениеАвг 09, 2011 13:00 
Ответить с цитатой
Не правы. Под утечкой имелось в виду не то, что список будет держать кучу объектов, а то, что в первом случае каждый объект из этой кучи ещё и будет иметь неявную ссылку на объект, его породивший, т.е. на Outer. Поэтому GC не сможет собрать не только Result'ы (т.к. ссылки на них находятся в списке), но и Outer'ы (т.к. ссылки на них находятся в Result'ах). Во втором случае Result не содержит ссылки на Outer и GC может их (Outer'ы) спокойно собирать
К началу Посмотреть профиль Отправить личное сообщение
Bandito2000 : 7
Новичок

СообщениеАвг 09, 2011 13:04 
Ответить с цитатой
Всё, теперь понял. Спасибо за разъяснение.
К началу Посмотреть профиль Отправить личное сообщение
 
Начать новую тему  Ответить на тему
Страница 2 из 2
На страницу Пред.  1, 2
Список форумов
 -> Разное


 
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Java and all Java-related trademarks and logos are trademarks or registered trademarks of Oracle Corporation in the United States and other countries.
Это сайт не относится к фирме Oracle Corporation и не поддерживается ею.

© 2006-2010 www.javatalks.ru: форум java программистов
Используется скрипт phpBB © 2001, 2010 phpBB Group

Хостинг от bizname.ru