Чи можна змусити збирати сміття на 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 ™ Virtual Machine Tool (JVM TI) , функція
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
"змусить ВМ здійснювати вивезення сміття." JVM TI є частиною архітектури налагодження платформи JavaTM (JPDA) .
ТАК майже неможливо змусити вас звертатися до методів у тому самому порядку, і при цьому ці:
System.gc ();
System.runFinalization ();
навіть якщо лише один об’єкт очистити використання цих двох методів, змушує одночасно збирач сміття використовувати finalise()
метод недосяжного об'єкта, звільняючи присвоєну пам'ять і виконуючи те, про що finalize()
йдеться в методі.
ЗАРАЗ страшна практика використовувати сміттєзбірник, оскільки його використання може спричинити надмірне навантаження на програмне забезпечення, яке може бути навіть гіршим, ніж на пам'яті, у сміттєзбірника є своя нитка, яку неможливо контролювати плюс залежно від алгоритм, який використовує gc, може зайняти більше часу і вважається дуже неефективним, ви повинні перевірити своє програмне забезпечення, якщо воно найгірше за допомогою gc, оскільки воно, безумовно, зламане, хороше рішення не повинно залежати від gc.
ПРИМІТКА: просто майте на увазі, це спрацює лише в тому випадку, якщо в методі доопрацювання не буде перепризначення об'єкта, якщо це станеться, об'єкт збережеться живим, він матиме воскресіння, яке технічно можливо.
gc()
це лише натяк на запуск сміття. runFinalizers()
запускає фіналізатори лише на об'єктах, "які було виявлено відкинутими". Якби gc насправді не працював, таких об’єктів може не бути ...
Згідно з документацією на OutOfMemoryError, він заявляє, що його не буде викинуто, якщо VM не зможе відновити пам'ять після повного збору сміття. Тож якщо ви будете продовжувати розподіляти пам’ять, поки не отримаєте помилку, ви вже змусили повноцінно збирати сміття.
Імовірно, питання, яке ви насправді хотіли задати, було "як я можу повернути пам'ять, на яку я думаю, що мені слід відшкодувати сміття?"
Щоб вручну подати запит на GC (не з System.gc ()):
.gc є кандидатом на усунення у майбутніх випусках - інженер Sun Sun одного разу прокоментував, що, можливо, менше ніж двадцять людей у світі насправді знають, як користуватися .gc () - я вчора ввечері кілька годин працював на центральній / критичній Структура даних за допомогою даних, згенерованих SecureRandom, десь близько 40 000 об'єктів vm сповільниться, як би у нього не було покажчиків. Зрозуміло, що він задушився на 16-бітних таблицях вказівників і демонстрував класичну поведінку "несправного обладнання".
Я спробував -Xms і так далі, продовжував трохи посміхатися, поки він не запустився до 57, xxx щось. Тоді він би запустив 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 викликати Garbage Collector.
Оскільки збирач сміття працює з віртуальною машиною, ми не можемо змусити його проводити очищення там і далі. Швидше, що ми ставимо чергу на наш запит зі смітником. Це залежить від віртуальної машини через певний час (це може змінюватися від системи до системи, як правило, коли порогова пам'ять, виділена 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, а не програмним поводженням з ним у вашій програмі.