2014-01-21 1 views
1

Итак, я немного обманывал время, затрачиваемое на создание Strings vs using StringBuilder, а также немного мусор с сборщиком мусора. Для меня, как студент CS первого года, сборщик мусора немного похож на меня тоже, как на меня, где он просто очищает все и «просто работает». Я был немного смущен, когда я пришел с этим:Сборщик мусора, строки и финализация путаницы

public class Main 
{ 

    public static void main(String[] args) 
    { 
     long time = System.currentTimeMillis(); 
     new Test(); 
     for (int i= 0; i < 10000; i++) 
     { 
      String s = "a"; 
      for (int c = 0; c < 26; c++) 
      { 
       s += (Character.toString((char) ('a' + c))); 
       //s += "testttzzz"; 
      } 
     } 
     System.out.println(System.currentTimeMillis() - time); 
    } 

} 

class Test 
{ 
    @Override 
    protected void finalize() throws Throwable 
    { 
     System.out.println("FINALIZE TEST!"); 
    } 
} 

Внутри кода выше, если раскомментировать из будет называться линия «s + =„testttzzz“сборщик мусора и будет выводить FINALIZE TEST!. Однако, если эта строка закомментирована, сборщик мусора не будет работать во время работы программы и вообще не будет выводить FINALIZE TEST!. Почему это?

Редактировать: Я попытался добавить System.out.println(i); внутри первого цикла цикла, чтобы я мог видеть, когда вызывается именно System.gc(). Похоже, что добавление этой строки привело к тому, что сборщик мусора больше не запускался. Я действительно смущен.

Edit2: Если это имеет значение, я использую JRE 1.7.0_45 и используя затмение версии 4.3.1 для компиляции кода

EDIT3: Я думаю, это только кажется, что добавленное время от дополнительных строк кода дает сборщик мусора больше времени для запуска и позволяет завершить finalize(). Интересно все же.

Edit4: Хорошо, согласно Джону Скиту, это не так. Сборщик мусора довольно интересен

+0

Это потому, что это не детерминированное поведение. Сборщик мусора отлично работает, он может не собираться, когда вы ожидаете, поэтому, если вы не настроите GC, вы не должны тратить на него слишком много времени. – Kayaman

+0

@ Кайайан Да, я вообще не очень разбираюсь в GC. Я просто подумал, что это что-то интересное и, возможно, причина в том, что это происходит иначе, чем просто непредсказуемость. – user2249516

+0

@arshajii Не, если программа заканчивается до запуска GC. Добавление большего количества кода приводит к запуску GC. – Kayaman

ответ

1

Без комментируемой части вы используете только полезную память около 260 КБ. В том числе накладные расходы, вы можете получить до 1 Мбайт сменных данных.

Я запустил вашу программу и проверил ее против VisualVM, чтобы узнать, что происходит.

VM начинается с размера кучи 63,5 МБ, поэтому у него есть это пространство, прежде чем ему понадобится выделить новое пространство. Программа начинается с использования памяти около 6,5 МБ, поэтому используется около 10% используемой памяти. В ходе программы использование памяти увеличивается до 8,1 МБ, поэтому я даю вам, что он был на 1,6 МБ, но все же это ничего. У VM осталось много места. Запуск GC теперь будет просто пустой тратой времени процессора.

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

Следующая вещь, которую я сделал, раскомментировать эту строку:

s += "testttzzz"; 

Теперь использование памяти пошел только чуть-чуть больше, но, казалось бы, достаточно, чтобы сделать его над «волшебной барьер» и GC побежал.

В GC есть несколько показателей, которые определяют, когда они запускаются, и те, которые отличаются от одной виртуальной машины, запускающей Java на другую.Некоторые из них являются:

  • Процента динамической памяти используется
  • скорости роста используемой памяти
  • Свободной оперативной памяти, которая может быть выделена для кучи
  • Текущего использование CPU

Вы сказали,

"сборщик мусора немного похож на магию тоже меня здесь он просто очищает все и «просто работает».

И это как раз то, как должно быть. В Java реализация GC зависит от человека, создавшего виртуальную машину. Нет стандарта, когда он должен работать. Существует метод System.gc(), но даже это не заставляет GC работать, а просто «предлагает», что сейчас самое подходящее время для запуска GC. Даже если вы используете одну и ту же виртуальную машину в другой системе, она может действовать совершенно иначе. В качестве примера: у меня есть 64-разрядная система Windows 7 с оперативной памятью 4 ГБ с 32-разрядной виртуальной машиной Java. Мой максимальный размер кучи по умолчанию составляет 903,12 МБ. У моей жены есть 64-разрядная система Windows 8 с 4 ГБ оперативной памяти, работающая с той же 32-разрядной виртуальной машиной Java. Ее максимальный размер кучи по умолчанию составляет всего 247,5 МБ! Это означает, что GC будет намного более ленивым в моей системе, чем на моей жене.

Как программист, вы можете доверять GC, чтобы выполнить его работу (очистить память, чтобы у вас было достаточно памяти для вашей программы), но не заставляйте какие-либо части вашей программы зависеть от GC, выполняемой каким-либо определенным образом, потому что это не нужно, и это, вероятно, не будет.

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