Вы должны иметь в виду, что сборщик мусора делает намного больше, чем просто собирает недоступные объекты.Он также оптимизирует пространство кучи и отслеживает точно , где есть доступная память для выделения для создания новых объектов.
Знание того, где есть свободная памятьделает эффективное выделение новых объектов молодому поколению эффективным и предотвращает необходимость бегать туда и обратно к базовой ОС.JIT Masamitsu из Sun, JIT-компилятор, также оптимизирует такие распределения вне уровня JVM:
При быстром распределении не требуется JVM для выделения объекта.JIT-компиляторы знают, как выделять из молодого поколения, и код для выделения генерируется встроенным для выделения объектов.Интерпретатор также знает, как выполнить выделение без вызова виртуальной машины.
Обратите внимание, что JVM делает все возможное, чтобы попытаться получить большие непрерывные блоки памяти, которые, вероятно, имеют их собственные преимущества в производительности (см. «Стоимость пропуска кэша»).Я полагаю, что вызовы malloc
(или альтернативы) имеют ограниченную вероятность предоставления непрерывной памяти между вызовами, но, возможно, я что-то там упустил.
Кроме того, поддерживая саму память, сборщик мусора может делать выделениеоптимизация на основе использования и моделей доступа.Теперь я понятия не имею, в какой степени это происходит, но, учитывая, что на эту концепцию зарегистрирован зарегистрированный Sun патент, я думаю, что они что-то с этим сделали.
Сохранение этой памятиВыделенные блоки также обеспечивают защиту для программы Java.Поскольку сборщик мусора скрыт от программиста, они не могут сказать JVM: «Нет, сохраните эту память; я закончил с этими объектами, но мне понадобится место для новых».Сохраняя память, GC не рискует отказаться от памяти, которую он не сможет вернуть.Естественно, вы всегда можете получить OutOfMemoryException
в любом случае, но кажется более разумным не возвращать память операционной системе без необходимости каждый раз, когда вы заканчиваете работу с объектом, поскольку вы уже потрудились получить его для себя.
Помимо всего этого, я постараюсь обратиться непосредственно к нескольким вашим комментариям:
Зачастую они занимают все больше и больше памяти во время выполнения.
Предполагая, что это не только то, что делает программа (по какой-то причине, может быть, она имеет утечку, может быть, она должна отслеживать растущий объем данных), я предполагаю, что это связано сотношение свободного пространства хеша по умолчанию, установленное JVM (Sun / Oracle).Значение по умолчанию для -XX:MinHeapFreeRatio
составляет 40%, а -XX:MaxHeapFreeRatio
- 70%.Это означает, что каждый раз, когда остается только 40% пространства кучи, размер кучи будет изменяться путем запроса дополнительной памяти операционной системы (при условии, что она не будет превышать -Xmx
).И наоборот, он только * освободит память кучи обратно в операционную систему, если свободное пространство превысит 70%.
Подумайте, что произойдет, если я выполню операцию с интенсивным использованием памяти в Eclipse;профилирование, например.Мое потребление памяти будет расти, изменяя размер кучи (вероятно, несколько раз) по пути.Когда я закончу, требования к памяти уменьшатся, но, скорее всего, они не упадут настолько, что 70% кучи свободны.Это означает, что теперь выделено много неиспользуемого пространства, которое JVM не собирается освобождать.Это серьезный недостаток, но вы можете обойти его, настроив проценты в вашей ситуации.Чтобы получить более полное представление об этом, вы действительно должны профилировать свое приложение, чтобы вы могли видеть используемое и выделенное пространство кучи.Я лично использую YourKit , но есть много хороших альтернатив на выбор.
* Я не знаю, действительно ли это только время и как это наблюдается с точки зрения ОС, но документация гласит это " Максимальный процент свободного кучи после GC до , избегая сокращения , "что, по-видимому, предполагает.
Даже очень маленький пример демо
приложения загружают огромное количество
память.
Полагаю, это зависит от того, какие приложения они используют. Я чувствую, что Java-приложения с графическим интерфейсом работают с большим объемом памяти, но у меня нет никаких доказательств, так или иначе. У вас был конкретный пример, на который мы могли бы взглянуть?
Но зачем загружать
библиотека для каждого экземпляра Java?
Ну, как бы вы справились с загрузкой нескольких приложений Java, если бы не создавали новые процессы JVM? Изоляция процессов - это хорошо, что означает независимую загрузку. Я не думаю, что это так необычно для процессов в целом.
В качестве заключительного замечания, время медленного запуска, о котором вы спрашивали в другом вопросе, вероятно, связано с несколькими перераспределениями начальной кучи, необходимыми для достижения базовых требований к памяти приложения (из-за -Xms
и -XX:MinHeapFreeRatio
), в зависимости от значения по умолчанию значения с вашей JVM.