Интересная работа сборщика мусора

    Проблема
    Явой занялся я недавно, и столкнулся с интересной проблемой связанной с динамическим переопределением методов во время исполнения. После выхода из переопределенного метода терялась ссылка на объект. Решение проблемы затянулось в связи с тем, что на одном компьютере она была, а на другом нет.


    Структура кода
    У меня есть класс Резидент.

    public class Resident {
      /*Variables*/
      int age;
      String trace;
      boolean live;
      int energy;
      String name;
      int id;
      int x;
      int y;
      World world;

      /*Body*/
      public void Turn() {
        age++;
      }
    }


    От класса Резидент наследуется Бот. И переопределяется метод Турн.

    public class Bot extends Resident {
      /*Variables*/
      Queue m;
      Vector moves = new Vector();

      /*Constrctors*/
      public Bot(int energy, String name, World world) {
        this.energy = energy;
        this.name = name;
        this.trace = "";
        if (this.energy < 1) {
          this.live = false;
        } else {
          live = true;
        }
        this.world = world;
        this.age = 0;
      }

      /*Body*/
      public void Turn() {
        age++;
        energy--;
        if (!moves.isEmpty()) {
          world.ResidentAction(this, (ACTION) moves.lastElement());
          moves.remove(moves.size() — 1);
        }
      }
    }


    В классе Ворлд имеем массив резидентов.

    public class World {
      /*Variables*/
      String name;
      int width;
      int height;
      Resident[][] residents;

      /*Constrctors*/
      public World(String name, int height, int width) {
        this.height = height;
        this.name = name;
        this.width = width;
        this.residents = new Resident[height][width];
      }

      /*Body*/
      public void AddBot() {
        Bot b = new Bot(100, "B", this);
        residents[1][2] = b;
        b.X(1);
        b.Y(2);
      }

      public void AddBot(Bot b) {
        residents[1][2] = b;
        b.X(1);
        b.Y(2);
      }

      public void AddBot(Bot b, int x, int y) {
        residents[x][y] = b;
        b.X(x);
        b.Y(y);
      }

      public void Turn() {
        for (int i = 0; i < width; i++) {
          for (int j = 0; j < height; j++) {
            if (residents[i][j] != null) {
              residents[i][j].Turn();
              if (!residents[i][j].isLive())
                residents[i][j] = null;
            }
          }
        }
      }
    }


    В Мейне. Создаем объект типа Ворлд и Бот, и запихиваем Бота в Ворлд по координатам 1,2. Потом пробуем выполнить метод Турн для ворлда.

    public class Programm {

      public static void main(String[] args) {
        World w = new World("Test1", 100, 100);
        Bot b = new Bote(20, "B", w)
        w.AddBot(b);
        w.Turn();

      }
    }


    * This source code was highlighted with Source Code Highlighter.

    Полсле выхода из residents[i][j].Turn(), residents[i][j] полчался равен null. И дальше все вылеталало по исключению. Как я и говорил на некоторых компах проблема была, а на некоторых нет.

    Почему
    Потому что Бот объявлен в классе Програм. И при входе в Турн метод бота ссылка на него теряется и уже на выходе сборщик мусора объект удаляет. Решается проблема либо так:

    public class Programm {
      static Bot b;
      
      public static void main(String[] args) {
        World w = new World(«Test1», 100, 100);
        b = new Bot(20, "", w);
        w.AddBot(b);
        w.Turn();

      }
    }


    * This source code was highlighted with Source Code Highlighter.
    Либо созданием бота в Ворлде через метод w.AddBot().

    ПС. Я могу быть не прав в определении причины сего. Буду рад услыщать мнения

    Средняя зарплата в IT

    120 000 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 3 502 анкет, за 1-ое пол. 2021 года Узнать свою зарплату
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 25

      +2
      АААА!!! Помогите.
      Что с хабром??? Я хотел сделать правку в статье, а он еще одну создал. Немогу скрыть. Немогу в черновики публикануть. Что с ним????
        0
        Я конечно полный лузер в Java, но разве в последнем листинге не должно быть b.Turn();?
          +1
          Я хочу что бы все турны выполнялись через Ворлд.

          ПС. И нахрена мне такое счастье… через эти глюки карма в говне… спасибо дорогое НЛО. два раза за день…
            0
            Ох, туплю, действительно :) Это конец хода видимо.
              0
              начало:)
          0
          public Bot(int energy, String name, World world) {
           //...  
           if (this.energy < 1) {
            this.live = false;
           } else {
            live = true;
           }
           //...
          }

          У Вас боты создаются мёртвыми независимо от переданной в конструктор энергии.
          Ну и World.Turn() их обнуляет.
            0
            Ну и сама эта конструкция являет собой отличный образчик индийского кода :)
            Может лучше всё же
            this.live = (energy>=1)
              0
              Забавно. У меня стоит IntelliJ IDEA. Инспектор кода предложил заменить мой if на this.live = (energy>=1). Забавно…
              0
              Bot b = new Bot(20, «B», w)
              Создавался с енергией 20, тоесть живой.
                0
                Сорри, не заметил «this.energy = energy» в первой строке конструктора.
              0
              ссылка не теряется — у вас же она хранится в residents[1][2]. поэтому никто её собрать не должен.

              код не падает, и не должен. хотя баги есть (например размерность массива [height][width], а используется как [width][height])
                0
                Но все же он падает… Причем как я говорил не на каждом компе.

                Милости просим. botworld.googlecode.com/svn/trunk/BotWorld/
                  0
                  я бы предположил, что падает из-за world.ResidentAction(this, (ACTION) moves.lastElement()) в Bot.
                  при этом обнуляется ссылка в массиве — что приведет к NRE при вызове isLive()
                    0
                    Да падает на isLive().
                    А что плохого в world.ResidentAction(this, (ACTION) moves.lastElement())?
                      0
                      там обнуляется элемент массива в некоторых кейсах (разве нет?), а в турн вы пытаетесь его использовать
                        +1
                        ААА!!! Точно. residents[res.X()][res.Y()] = null;
                        Большое спасибо!
                        А как же оно работало на других компах????
                          0
                          также, просто этот кейс не выпадал на исполнение скорее всего
                            0
                            выпадал 100%. код не менялся. ВОт там сборщик работал действительно странно.:)
                              0
                              забудьте про сборщик. в 99.99% случаях код фреймворка работает верно
                                0
                                Завтра протестирую на том компе, на котором не вылитало исключение и отпишусь.
                                Еще раз спасибо за полезный опыт.
                                  0
                                  Все оказалось просто, ошибка в логике. Мой напарник, который тестил этот код и у которого небыло ошибки, просто удалил кусок кода в котором вносились хода в лист. Ходов небыло, перемещений небыло, исключений небыло… вот и все.
                            0
                            Нужно вместо
                            residents[i][j]).Turn();
                            if(!residents[i][j].isLive()) residents[i][j] = null;

                            написать
                            if(!residents[i][j].isLive()) residents[i][j] = null;
                            else{
                            residents[i][j]).Turn();
                            }
                      0
                      Спасибо. Сам бы не нашел.
                      +1
                      Название топика звучит как отличная вакансия =)
                        0
                        ага. забавно:)

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое