На собеседовании мне задали вопрос - "Как помочь сборщику мусора при написании кода?".
На мой взгляд, GC работает очень хорошо, и нам не нужно использовать что-то большее, чем базовые хорошие практики кода, позже добавил, что закрытие ресурсов в блоке finally наверняка поможет GC, но в целом был удивлен таким вопросом.
Есть хороший ответ? Нужно ли нам делать что-то невероятное, чтобы помочь сборщику мусора?
Когда мы мешаем сборщику мусора делать свою работу? когда мы пропускаем объекты, которые больше не используются (с анонимными классами или статическими ссылками)
Это действительно странный вопрос. Разве предотвращение работы коллекционера не считается помощью? Потому что это то, что делает большинство из этих вещей.
Сборщик мусора очень эффективен и ловок в своей работе, но мы можем усилить его способность собирать мусор, указывая на null переменные и объекты, которые больше не используются и на них больше нет ссылок.
При работе с файлами используйте методы close()
и flush()
.
И при обработке потоков уничтожайте поток, когда он не используется.
Вы имеете в виду установку, например, anyVariable = null;
, когда мы ее больше не используем? Я не думаю, что это хорошая практика.
@ Michu93 Это то, что имел в виду Яш. Если на объект нет ссылок, он может быть удален сборщиком мусора. Если вы следуете другим хорошим практикам (небольшие методы, локальные переменные и т. д.), это на самом деле не нужно - если область действия переменной как можно меньше, то это не проблема.
Если это не сработает, то, чтобы помочь gc, мы могли бы ограничить создание объекта классом singleton. Что об этом говорят
Это действительно кажется немного неудобным вопросом, поскольку Java известна своей техникой сборки мусора.
Сборщик мусора — это «задача», которая периодически сканирует ваши объекты, чтобы обнаружить, что не используется (на самом деле это механизм для эмуляции машины с бесконечной памятью).
По этой причине, когда вы держите ссылку на экземпляр объекта, который вам больше не нужен, вы должны установить для него значение null
, чтобы сборщик мусора знал, что вас больше не интересует этот экземпляр (и, возможно, его потомки).
Это не означает, что вы должны устанавливать каждую переменную в null
после использования, но вы должны следить за полями.
Поскольку в Java нет шаблона удаления (см. здесь для получения дополнительной информации), вы должны разработать свои API, чтобы имитировать его: когда вы закончите использовать экземпляр объекта, содержащий ссылку, которую вы хотите освободить, вы должны добавить соответствующий метод совершить такое действие.
Рассмотрим следующий пример:
class MyClass1
{
int Field1;
int Field2;
int Field3;
int Field4;
}
class MyClass2
{
private MyClass1 m_MyReference;
public MyClass2()
{
m_MyReference = new MyClass1();
}
public void DoSomething()
{
// do something here that uses m_MyReference.
}
}
Если экземпляр MyClass2 удерживается, но какой-либо другой доступный экземпляр вашей программы (например, синглтон или какой-либо экземпляр, находящийся в настоящее время в стеке), вы никогда не освободите память, связанную с MyClass1, поскольку на него все еще ссылается m_MyReference
.
Это плохо? Это зависит от того, что MyClass2 и MyClass1 действительно делают.
Если вы знаете, что MyClass2 может иметь очень долгий срок службы, и вы хотите сохранить ссылку на MyClass2, но освободить память, связанную с MyClass1, вам нужно сделать что-то похожее на код ниже:
class MyClass2
{
private MyClass1 m_MyReference;
public MyClass2()
{
m_MyReference = new MyClass1();
}
public void DoSomething()
{
// do something here that uses m_MyReference.
}
public void Dispose()
{
m_MyReference = null;
}
}
Таким образом, вы предоставляете вызывающей стороне способ сигнализировать о том, что у вас больше нет ссылки на экземпляры, которые вам не нужны.
Помните, что простое присвоение null
переменной или полю не освобождает память автоматически. Сборщик мусора является асинхронным и запускается по своему усмотрению.
Надеюсь, что дал идею, не вдаваясь слишком глубоко.
В большинстве случаев вам не нужно явно обнулять ссылки в помощь ГК, потому что время жизни объекта обычно связано. т.е. экземпляр MyClass2
в вашем случае часто становится недоступным вскоре после окончания его жизненного цикла (удаления). Конечно, есть исключения. Но редко вы продолжаете использовать объект и устанавливаете значение null только для одного из его полей только для того, чтобы помочь сборщику мусора. см. stackoverflow.com/q/449409/1362755 для более подробной информации.
Вы правы, уровень и точность ответа должны соответствовать ответу. С моей точки зрения, достаточно просто делать «правильные вещи», поэтому мой ответ был в этом направлении. Включение таких деталей, как достижимость дерева, замыкания и т. д., не помогает писать хороший код, а просто сообщает вам о неконтрактных деталях GC, что, в конце концов, является оптимизацией.
На самом деле, вы усугубляете ситуацию, так как теперь оптимизатор должен признать, что ваш m_MyReference = null;
устарел, иначе это назначение поддерживает экземпляр MyClass2
дольше, чем необходимо. Если вы ожидаете, что кто-то сохранит ссылку на экземпляр MyClass2
, несмотря на то, что он вызвал dispose()
для него, вам следует переосмыслить дизайн программного обеспечения. Рекомендуемое чтение: Может ли java завершить объект, когда он все еще находится в области видимости? • finalize() вызывается для сильно достижимых объектов
Странно сформулирован вопрос. ГК не нуждается в помощи в своей работе. Он будет работать с любыми ограничениями, наложенными на него, или потерпит неудачу, если ограничения не могут быть соблюдены.
Конечно, работу можно переделать, но это делается не из желания облегчить нагрузку на ГК — не человеку надоедает его работа, — а из каких-то скрытых побуждений, вроде улучшения программы в целом. представление.
Эти вещи обычно определяются как задержка, энергопотребление, пропускная способность или оптимизация памяти. Но это не единственные показатели, которые волнуют программиста. Простота и читаемость кода также имеют значение.
Наивный код может быть более читабельным, но менее производительным. Если вашей целью является легко читаемый код, то выполнение сложных оптимизаций, снижающих нагрузку на сборщик мусора, может привести к обратным результатам, и поэтому «помощь сборщику мусора» не является самоцелью.
Теперь, если ваша цель — улучшить некоторые показатели производительности, то некоторые оптимизации также включают в себя написание кода, который уменьшает работу, выполняемую подсистемой управления памятью (распределение + GC). Некоторые возможные оптимизации включают отказ от финализаторов, обнаружение утечек памяти, сокращение ненужных выделений, отказ от огромных массивов Object[], настройку параметров GC, покупку лучшего оборудования и сокращение времени жизни объектов. Какая оптимизация применима, зависит от приложения и может быть лучше всего выяснена с помощью профилировщиков, ведения журнала GC и связанных с ними
Очень расплывчатый вопрос для интервью. Также зависит от того, какой сборщик мусора используется.