Управление памятью в Java Интервью Вопросы (ответы)

Управление памятью в Java. Вопросы для интервью (+ ответы)

1. Вступление

В этой статье мы рассмотрим некоторые вопросы по управлению памятью, которые часто возникают во время собеседований с разработчиками Java. Управление памятью - это область, с которой не так много разработчиков знакомо.

Фактически, разработчикам обычно не приходится иметь дело с этой концепцией напрямую, поскольку JVM заботится о мельчайших деталях. Если что-то не идет серьезно не так, даже опытные разработчики могут не иметь точной информации об управлении памятью под рукой.

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

2. Вопросы

Q1. Что означает утверждение «Управление памятью в Java»?

Память - это ключевой ресурс, который требуется приложению для эффективной работы, и, как и любой ресурс, его мало. Таким образом, его распределение и освобождение от приложений или от других частей приложения требуют большой осторожности и внимания.

Однако в Java разработчику не нужно явно выделять и освобождать память - JVM и, в частности, сборщик мусора - отвечает за выделение памяти, так что разработчику не нужно этого делать.

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

Q2. Что такое сборка мусора и в чем ее преимущества?

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

Используемый объект или ссылочный объект означает, что некоторая часть вашей программы все еще поддерживает указатель на этот объект. На неиспользуемый объект или на объект, на который нет ссылок, больше не ссылается ни одна часть вашей программы. Таким образом, память, используемая объектом, на который нет ссылок, может быть восстановлена.

Самым большим преимуществом сборки мусора является то, что он снимает с нас бремя ручного выделения / освобождения памяти, чтобы мы могли сосредоточиться на решении проблемы под рукой.

Q3. Есть ли недостатки у сборки мусора?

Yes. Каждый раз, когда запускается сборщик мусора, он влияет на производительность приложения. Это связано с тем, что все остальные потоки в приложении должны быть остановлены, чтобы позволить потоку сборщика мусора эффективно выполнять свою работу.

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

Q4. Что означает термин «стоп-мир»?

Когда поток сборщика мусора работает, другие потоки останавливаются, то есть приложение на мгновение останавливается. Это аналогично уборке дома или фумигации, когда жильцам отказано в доступе до завершения процесса.

В зависимости от потребностей приложения сборка мусора «останови мир» может привести к недопустимому замораживанию. Вот почему важно выполнить настройку сборщика мусора и оптимизацию JVM, чтобы обнаруженное зависание было как минимум приемлемым.

Q5. Что такое стек и куча? Что хранится в каждой из этих структур памяти и как они взаимосвязаны?

Стек является частью памяти, которая содержит информацию о вызовах вложенных методов вплоть до текущей позиции в программе. Он также содержит все локальные переменные и ссылки на объекты в куче, определенные в выполняемых в настоящее время методах.

Эта структура позволяет среде выполнения возвращаться из метода, зная адрес, откуда он был вызван, а также очищать все локальные переменные после выхода из метода. Каждый поток имеет свой собственный стек.

Куча - это большой объем памяти, предназначенный для размещения объектов. Когда вы создаете объект с ключевым словомnew, он выделяется в куче. Однако ссылка на этот объект живет в стеке.

Сборка мусора поколений может быть в общих чертах определена как стратегия, используемая сборщиком мусора, где куча делится на несколько разделов, называемых поколениями, каждый из которых будет содержать объекты в соответствии с их «возрастом» в куче.

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

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

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

Сегодня почти все сборщики мусора являются поколениями. Эта стратегия очень популярна, потому что со временем она оказалась оптимальным решением.

Q7. Подробно опишите, как работает сборка мусора из поколения в поколение

Чтобы правильно понять, как работает поколенческая сборка мусора, важно сначала использоватьremember how Java heap is structured, чтобы облегчить поколенческую сборку мусора.

Куча делится на меньшие пространства или поколения. Эти места - молодое поколение, старое или постоянное поколение и постоянное поколение.

young generation hosts most of the newly created objects. Эмпирическое исследование большинства приложений показывает, что большинство объектов быстро недолговечны и, следовательно, вскоре становятся пригодными для сбора. Следовательно, новые объекты начинают свое путешествие здесь и «продвигаются» в пространство старого поколения только после того, как они достигли определенного «возраста».

Термин“age” в генеральной сборке мусораrefers to the number of collection cycles the object has survived.

Пространство молодого поколения далее делится на три пространства: пространство Эдема и два пространства выживших, такие как Оставшийся в живых 1 (s1) и Оставшийся в живых 2 (s2).

old generation hosts objects thathave lived in memory longer than a certain “age”. Объекты, которые пережили сборку мусора от молодого поколения, продвигаются в это пространство. Это обычно больше, чем у молодого поколения. Так как он больше по размеру, сборка мусора обходится дороже и происходит реже, чем у молодого поколения.

permanent generationor more commonly called, PermGen, contains metadata required by the JVM для описания классов и методов, используемых в приложении. Он также содержит пул строк для хранения внутренних строк. Он заполняется JVM во время выполнения на основе классов, используемых приложением. Кроме того, здесь могут храниться классы и методы библиотеки платформы.

Во-первых,any new objects are allocated to the Eden space. Оба места выживших начинаются пустыми. Когда пространство Eden заполняется, запускается небольшая сборка мусора. Объекты, на которые есть ссылки, перемещаются в первое пространство выживших. Объекты без ссылок удаляются.

Во время следующего второстепенного GC то же самое происходит с пространством Эдема. Объекты, на которые нет ссылок, удаляются, а объекты, на которые есть ссылки, перемещаются в область оставшихся в живых. Однако в этом случае они перемещаются во второе пространство выживших (S2).

Кроме того, у объектов из последнего младшего GC в первом пространстве выживших (S1) возраст увеличивается и перемещается на S2. Как только все выжившие объекты были перемещены на S2, и пространство S1, и пространство Eden очищаются. На этом этапе S2 содержит объекты разного возраста.

На следующем второстепенном GC тот же процесс повторяется. Однако на этот раз выжившие пространства переключаются. Объекты, на которые есть ссылки, перемещаются в S1 как из Eden, так и из S2. Выжившие объекты в возрасте. Иден и S2 очищены.

После каждого незначительного цикла сборки мусора проверяется возраст каждого объекта. Те, кто достиг определенного произвольного возраста, например, 8 лет, продвигаются от молодого поколения к старому или постоянному поколению. Для всех последующих второстепенных циклов GC объекты будут по-прежнему продвигаться в пространство старого поколения.

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

Q8. Когда объект получает право на сборку мусора? Опишите, как Gc собирает подходящий объект?

Объект получает право на сборку мусора или сборщик мусора, если он недоступен из каких-либо активных потоков или статических ссылок.

Самый простой случай, когда объект получает право на сборку мусора, это если все его ссылки равны нулю. Циклические зависимости без какой-либо живой внешней ссылки также имеют право на GC. Таким образом, если объект A ссылается на объект B, а объект B ссылается на объект A и у них нет никакой другой действующей ссылки, то оба объекта A и B будут иметь право на сборку мусора.

Другой очевидный случай - когда родительский объект имеет значение null. Когда кухонный объект внутренне ссылается на объект холодильника и объект раковины, а для объекта кухни установлено нулевое значение, и холодильник, и раковина получат право на сбор мусора вместе со своей родительской кухней.

Q9. Как запустить сборку мусора из кода Java?

You, as Java programmer, can not force garbage collection in Java; он сработает, только если JVM сочтет, что ему нужна сборка мусора на основе размера кучи Java.

Перед удалением объекта из памяти поток сборки мусора вызывает метод finalize () этого объекта и дает возможность выполнить любую необходимую очистку. Вы также можете вызвать этот метод объектного кода, однако нет никакой гарантии, что при вызове этого метода будет происходить сборка мусора.

Кроме того, существуют методы, такие как System.gc () и Runtime.gc (), которые используются для отправки запроса сборки мусора в JVM, но не гарантируется, что сборка мусора произойдет.

Q10. Что происходит, если места в куче не хватает для хранения новых объектов?

Если нет места в памяти для создания нового объекта в куче, виртуальная машина Java выдаетOutOfMemoryError или, точнее,java.lang.OutOfMemoryError heap space.

Q11. Можно ли «воскресить» объект, который стал подходящим для сборки мусора?

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

В методеfinalize вы можете технически «воскресить» объект, например, назначив его полюstatic. Объект снова станет живым и непригодным для сбора мусора, поэтому сборщик мусора не будет собирать его во время следующего цикла.

Однако объект будет помечен как завершенный, поэтому, когда он снова станет подходящим, метод финализации не будет вызван. По сути, вы можете повернуть этот трюк «воскрешения» только один раз за время существования объекта. Помните, что этот уродливый прием следует использовать только в том случае, если вы действительно знаете, что делаете, однако понимание этого трюка дает некоторое представление о том, как работает сборщик мусора.

Q12. Опишите сильные, слабые, мягкие и фантомные ссылки и их роль в сборке мусора.

Поскольку память управляется в Java, инженеру может потребоваться как можно больше оптимизации, чтобы минимизировать задержки и максимально увеличить пропускную способность в критически важных приложениях. Как иit is impossible to explicitly control when garbage collection is triggered в JVM,it is possible to influence how it occurs as regards the objects we have created.

Java предоставляет нам ссылочные объекты для управления отношениями между объектами, которые мы создаем, и сборщиком мусора.

По умолчанию на каждый объект, который мы создаем в программе Java, строго ссылается переменная:

StringBuilder sb = new StringBuilder();

В приведенном выше фрагменте ключевое словоnew создает новый объектStringBuilder и сохраняет его в куче. Затем переменнаяsb сохраняетstrong reference в этот объект. Для сборщика мусора это означает, что конкретный объектStringBuilder вообще не имеет права на сборку из-за сильной ссылки на негоsb. История меняется только тогда, когда мы обнуляемsbследующим образом:

sb = null;

После вызова вышеуказанной строки объект будет иметь право на сбор.

Мы можем изменить эту связь между объектом и сборщиком мусора, явно заключив его в другой объект ссылки, который находится внутри пакетаjava.lang.ref.

soft reference можно создать для указанного выше объекта следующим образом:

StringBuilder sb = new StringBuilder();
SoftReference sbRef = new SoftReference<>(sb);
sb = null;

В приведенном выше фрагменте мы создали две ссылки на объектStringBuilder. Первая строка создаетstrong referencesb, а вторая строка создаетsoft referencesbRef. Третья строка должна сделать объект подходящим для сбора, но сборщик мусора отложит его сбор из-заsbRef.

Ситуация изменится только тогда, когда станет не хватать памяти и JVM окажется на грани выдачи ошибкиOutOfMemory. Другими словами, объекты с только мягкими ссылками собираются в качестве последнего средства для восстановления памяти.

weak reference можно создать аналогичным образом, используя классWeakReference. Когдаsb имеет значение null, а объектStringBuilder имеет только слабую ссылку, сборщик мусора JVM не будет иметь никаких компромиссов и немедленно соберет объект в следующем цикле.

phantom reference похож на слабую ссылку, и объект только с фантомными ссылками будет собран без ожидания. Тем не менее, фантомные ссылки ставятся в очередь, как только их объекты собраны. Мы можем опросить справочную очередь, чтобы точно знать, когда объект был собран.

Q13. Предположим, у нас есть круговая ссылка (два объекта, которые ссылаются друг на друга). Может ли такая пара объектов стать подходящей для сборки мусора и почему?

Да, пара объектов с циклической ссылкой может получить право на сборку мусора. Это связано с тем, как сборщик мусора Java обрабатывает циклические ссылки. Он считает объекты живыми не тогда, когда они имеют какую-либо ссылку на них, а когда они достижимы путем навигации по графу объектов, начиная с некоторого корня сборки мусора (локальной переменной живого потока или статического поля). Если пара объектов с круговой ссылкой недоступна из любого корня, она считается пригодной для сборки мусора.

Q14. Как строки представлены в памяти?

ЭкземплярString в Java - это объект с двумя полями: полемchar[] value и полемint hash. Полеvalue представляет собой массив символов, представляющих саму строку, а полеhash содержитhashCode строки, которая инициализируется нулем, вычисленным в течение первогоhashCode() call и кешируется с тех пор. В качестве любопытного крайнего случая, еслиhashCode строки имеет нулевое значение, его нужно пересчитывать каждый раз, когда вызываетсяhashCode().

Важно то, что экземплярString является неизменным: вы не можете получить или изменить базовый массивchar[]. Еще одной особенностью строк является то, что строки статических констант загружаются и кэшируются в пуле строк. Если у вас есть несколько идентичных объектовString в исходном коде, все они представлены одним экземпляром во время выполнения.

Q15. Что такое Stringbuilder и каковы варианты его использования? В чем разница между присоединением строки к Stringbuilder и объединением двух строк с оператором +? Чем Stringbuilder отличается от Stringbuffer?

StringBuilder позволяет управлять последовательностями символов, добавляя, удаляя и вставляя символы и строки. Это изменяемая структура данных, в отличие от классаString, который является неизменным.

При объединении двух экземпляровString создается новый объект и копируются строки. Это может привести к огромным накладным расходам сборщика мусора, если нам нужно создать или изменить строку в цикле. StringBuilder позволяет намного эффективнее обрабатывать строковые манипуляции.

StringBuffer отличается отStringBuilder тем, что он потокобезопасен. Если вам нужно управлять строкой в ​​одном потоке, используйте вместо этогоStringBuilder.

3. Заключение

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

Это следует рассматривать не как исчерпывающий список вопросов, а как стартовую площадку для дальнейших исследований. Мы, например, желаем успехов в любых предстоящих интервью.