Можно ли форсировать сборку мусора в Java, даже если это сложно сделать? Я знаю , о System.gc();
и , Runtime.gc();
но они только предлагают сделать GC. Как я могу заставить GC?
Можно ли форсировать сборку мусора в Java, даже если это сложно сделать? Я знаю , о System.gc();
и , Runtime.gc();
но они только предлагают сделать GC. Как я могу заставить GC?
Ответы:
Ваш лучший вариант - это вызов, System.gc()
который просто является подсказкой сборщику мусора о том, что вы хотите, чтобы он делал сбор. Нет никакого способа принудительного и немедленного сбора, поскольку сборщик мусора недетерминирован.
non-deterministic == trouble
GC.Collect()
не собирает. В Java это gc()
делает.
Библиотека jlibs имеет хороший служебный класс для сборки мусора . Вы можете форсировать сборку мусора, используя хитрый трюк с объектами WeakReference .
RuntimeUtil.gc () из jlibs:
/**
* This method guarantees that garbage collection is
* done unlike <code>{@link System#gc()}</code>
*/
public static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get() != null) {
System.gc();
}
}
PhantomReference
с, ReferenceQueue
и вы получите уведомление после завершения, но еще до очистки. Наконец, даже если вы успешно обнаружите, что память для этого объекта была восстановлена, это все равно будет означать очень мало в поколенческом GC, подобном HotSpot. Обычно это совпадает с уборкой молодого поколения.
System.gc(); System.gc();
, но было бы интересно узнать, работает ли это когда-либо лучше, чем это. На самом деле, достаточно просто напечатать, сколько раз он звонил System.gc()
. Шанс когда-либо достичь 2 довольно мал.
Лучший (если не единственный) способ заставить GC - написать пользовательскую JVM. Я считаю, что сборщики мусора являются подключаемыми, так что вы можете просто выбрать одну из доступных реализаций и настроить ее.
Примечание: это не простой ответ.
Используя интерфейс виртуальной машины Java ™ (JVM TI) , функцию
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
«Принудительно заставит виртуальную машину выполнить сборку мусора». TI JVM является частью архитектуры отладчика платформы JavaTM (JPDA) .
ДА, почти возможно заставить вас вызывать методы в том же порядке, и в то же время это:
System.gc ();
System.runFinalization ();
даже если один и тот же объект очищает использование этих двух методов одновременно, вынуждает сборщик мусора использовать finalise()
метод недоступного объекта, освобождая назначенную память и делая то, что finalize()
утверждает метод.
ОДНАКО это ужасная практика использования сборщика мусора, потому что его использование может привести к перегрузке программного обеспечения, которая может быть даже хуже, чем к памяти, сборщик мусора имеет свой собственный поток, который невозможно контролировать плюс в зависимости от Алгоритм, используемый gc, может занять больше времени и считается очень неэффективным. Вы должны проверить свое программное обеспечение, если оно хуже с помощью gc, потому что оно определенно сломано, и хорошее решение не должно зависеть от gc.
ПРИМЕЧАНИЕ: просто помните, что это будет работать только в том случае, если в методе finalize нет переназначения объекта, если это произойдет, объект останется в живых и произойдет воскресение, что технически возможно.
gc()
это только подсказка для запуска сборки мусора. runFinalizers()
финализаторы запускаются только на объектах, "которые были найдены как отброшенные". Если gc на самом деле не запускался, таких объектов может не быть ...
В документации для OutOfMemoryError он заявляет, что он не будет выброшен, если виртуальная машина не смогла восстановить память после полной сборки мусора. Таким образом, если вы продолжите выделять память до тех пор, пока не получите сообщение об ошибке, вы уже запустите полную сборку мусора.
Предположительно, вопрос, который вы действительно хотели задать, был: «Как я могу восстановить память, которую, как мне кажется, я должен вернуть, путем сбора мусора?»
Чтобы вручную запросить GC (не из System.gc ()):
.gc - кандидат на исключение в будущих выпусках - инженер Sun однажды заметил, что, возможно, менее двадцати человек в мире действительно знают, как использовать .gc () - вчера вечером я несколько часов работал над центральным / критическим структура данных, использующая данные, сгенерированные SecureRandom, где-то чуть дальше 40 000 объектов, виртуальная машина замедлится, как если бы в ней не было указателей. Ясно, что он подавлял 16-битные таблицы указателей и демонстрировал классическое поведение «сбойного механизма».
Я пробовал -Xms и так далее, продолжал немного вертеться, пока не достигнет 57, ххх что-то. Затем он будет запускать gc, скажем, с 57 127 до 57 128 после gc () - примерно с тем же темпом вздутия кода в лагере Easy Money.
Ваш дизайн нуждается в фундаментальной переработке, возможно, в подходе с раздвижными окнами.
Вы можете запустить GC из командной строки. Это полезно для пакета / crontab:
jdk1.7.0/bin/jcmd <pid> GC.run
Видеть :
Спецификация JVM не говорит ничего конкретного о сборке мусора. Благодаря этому поставщики могут свободно внедрять GC по-своему.
Таким образом, эта неопределенность вызывает неопределенность в поведении сборки мусора. Вы должны проверить детали JVM, чтобы узнать о подходах / алгоритмах сбора мусора. Также есть опции для настройки поведения.
Если вам нужно форсировать сборку мусора, возможно, вам следует подумать о том, как вы управляете ресурсами. Вы создаете большие объекты, которые сохраняются в памяти? Вы создаете большие объекты (например, графические классы), которые имеют Disposable
интерфейс и не вызывают, dispose()
когда закончите с ним? Вы объявляете что-то на уровне класса, что вам нужно только в одном методе?
Было бы лучше, если бы вы описали причину, по которой вам нужна сборка мусора. Если вы используете SWT, вы можете использовать такие ресурсы, как Image
и Font
для освобождения памяти. Например:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
Есть также инструменты для определения нераспределенных ресурсов.
Если у вас заканчивается память и OutOfMemoryException
вы можете получить ее , попробуйте увеличить объем кучи, доступной для Java, запустив программу java -Xms128m -Xmx512m
вместо просто java
. Это даст вам начальный размер кучи 128 МБ и максимум 512 МБ, что намного больше, чем стандартные 32 МБ / 128 МБ.
java -Xms512M -Xmx1024M
Другой вариант - не создавать новые объекты.
Объединение объектов не требуется, чтобы уменьшить необходимость GC в Java.
Пул объектов обычно не будет быстрее создания объектов (особенно для легких объектов), но он быстрее, чем сборщик мусора. Если вы создали 10000 объектов, и каждый объект был 16 байтов. Это 160 000 байтов, которые GC должен восстановить. С другой стороны, если вам не нужны все 10 000 одновременно, вы можете создать пул для переработки / повторного использования объектов, что устраняет необходимость в создании новых объектов и устраняет необходимость в GC старых объектов.
Как то так (не проверено). И если вы хотите, чтобы он был потокобезопасным, вы можете поменять LinkedList на ConcurrentLinkedQueue.
public abstract class Pool<T> {
private int mApproximateSize;
private LinkedList<T> mPool = new LinkedList<>();
public Pool(int approximateSize) {
mApproximateSize = approximateSize;
}
public T attain() {
T item = mPool.poll();
if (item == null) {
item = newInstance();
}
return item;
}
public void release(T item) {
int approxSize = mPool.size(); // not guaranteed accurate
if (approxSize < mApproximateSize) {
recycle(item);
mPool.add(item);
} else if (approxSize > mApproximateSize) {
decommission(mPool.poll());
}
}
public abstract T newInstance();
public abstract void recycle(T item);
public void decommission(T item) { }
}
В OracleJDK 10 с G1 GC один вызов System.gc()
заставит GC очистить старую коллекцию. Я не уверен, что GC запускается немедленно. Однако GC не будет очищать коллекцию Young, даже если она System.gc()
вызывается многократно. Чтобы заставить GC очистить коллекцию Young, вы должны распределить в цикле (например, new byte[1024]
без вызова) System.gc()
. Призыв System.gc()
по какой-то причине не позволяет GC очистить коллекцию Young.
На самом деле, я не понимаю тебя. Но чтобы быть ясным в «Создании бесконечных объектов», я имел в виду, что в моей большой системе есть какой-то фрагмент кода, создающий объекты, которые обрабатывают и живые в памяти, на самом деле я не смог получить этот фрагмент кода, просто жест !!
Это правильно, только жест. У вас есть почти стандартные ответы, которые уже даны несколькими авторами. Давайте возьмем это по одному:
Правильно, фактического jvm нет - такова только спецификация, связка компьютерных наук, описывающая желаемое поведение ... Недавно я начал копать инициализацию объектов Java из нативного кода. Чтобы получить то, что вы хотите, единственный способ сделать то, что называется агрессивным обнулением. Ошибки, если они сделаны неправильно, настолько плохи, что мы должны ограничиться первоначальным объемом вопроса:
Большинство постеров здесь предполагают, что вы говорите, что работаете с интерфейсом, если это так, мы должны были бы увидеть, передается ли вам весь объект или один элемент за раз.
Если вам больше не нужен объект, вы можете присвоить ему значение null, но если вы ошиблись, возникнет исключение нулевого указателя. Бьюсь об заклад, вы можете добиться лучшей работы, если вы используете NIO
Каждый раз, когда вы, я или кто-либо еще получаете: « Пожалуйста, мне это ужасно нужно». Это почти универсальный предшественник почти полного уничтожения того, над чем вы пытаетесь работать… напишите нам небольшой пример кода, очищающий от него любое Фактический код используется и покажите нам свой вопрос.
Не расстраивайся. Часто это решает то, что ваш dba использует купленный где-то пакет, и оригинальный дизайн не настроен для массивных структур данных.
Это очень распространено.
FYI
Вызов метода System.runFinalizersOnExit (true) гарантирует, что методы финализатора будут вызваны до завершения работы Java. Однако этот метод по своей сути небезопасен и является устаревшим. Альтернативой является добавление «ловушек отключения» с помощью метода Runtime.addShutdownHook.
Масаррат Сиддики
Есть некоторый косвенный способ заставить сборщик мусора. Вам просто нужно заполнить кучу временными объектами до момента запуска сборщика мусора. Я сделал класс, который заставляет сборщик мусора таким образом:
class GarbageCollectorManager {
private static boolean collectionWasForced;
private static int refCounter = 0;
public GarbageCollectorManager() {
refCounter++;
}
@Override
protected void finalize() {
try {
collectionWasForced = true;
refCounter--;
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int forceGarbageCollection() {
final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
int iterationsUntilCollected = 0;
collectionWasForced = false;
if (refCounter < 2)
new GarbageCollectorManager();
while (!collectionWasForced) {
iterationsUntilCollected++;
int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
arr = null;
}
return iterationsUntilCollected;
}
}
Использование:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
Я не знаю, насколько этот метод полезен, потому что он постоянно заполняет кучу, но если у вас есть критически важное приложение, которое ДОЛЖНО форсировать GC - когда это может быть Java-способ форсировать GC.
Я хотел бы добавить кое-что здесь. Обратите внимание, что Java работает на виртуальной машине, а не на реальной машине. Виртуальная машина имеет свой собственный способ связи с машиной. Это может меняться от системы к системе. Теперь, когда мы вызываем GC, мы просим виртуальную машину Java вызвать сборщик мусора.
Поскольку сборщик мусора работает с виртуальной машиной, мы не можем заставить ее выполнить очистку тут же. Скорее, мы ставим наш запрос в очередь на сборщик мусора. Это зависит от виртуальной машины, после определенного времени (это может измениться от системы к системе, как правило, когда пороговая память, выделенная для JVM заполнена), фактическая машина освободит пространство. : D
Следующий код взят из метода assertGC (...). Он пытается заставить недетерминированный сборщик мусора собирать.
List<byte[]> alloc = new ArrayList<byte[]>();
int size = 100000;
for (int i = 0; i < 50; i++) {
if (ref.get() == null) {
// Test succeeded! Week referenced object has been cleared by gc.
return;
}
try {
System.gc();
} catch (OutOfMemoryError error) {
// OK
}
try {
System.runFinalization();
} catch (OutOfMemoryError error) {
// OK
}
// Approach the jvm maximal allocatable memory threshold
try {
// Allocates memory.
alloc.add(new byte[size]);
// The amount of allocated memory is increased for the next iteration.
size = (int)(((double)size) * 1.3);
} catch (OutOfMemoryError error) {
// The amount of allocated memory is decreased for the next iteration.
size = size / 2;
}
try {
if (i % 3 == 0) Thread.sleep(321);
} catch (InterruptedException t) {
// ignore
}
}
// Test failed!
// Free resources required for testing
alloc = null;
// Try to find out who holds the reference.
String str = null;
try {
str = findRefsFromRoot(ref.get(), rootsHint);
} catch (Exception e) {
throw new AssertionFailedErrorException(e);
} catch (OutOfMemoryError err) {
// OK
}
fail(text + ":\n" + str);
Источник (я добавил некоторые комментарии для ясности): Пример NbTestCase
Вы можете попробовать использовать Runtime.getRuntime().gc()
или использовать служебный метод. System.gc()
Примечание. Эти методы не гарантируют GC. И их область должна быть ограничена JVM, а не программно обрабатывать это в вашем приложении.