Чому погана практика викликати System.gc ()?


326

Після відповіді на запитання про те, як змусити об'єкти на Java на Java (хлопець очищав 1,5 Гб HashMap) System.gc(), мені сказали, що це погана практика дзвонити System.gc()вручну, але коментарі були не зовсім переконливими. Крім того, начебто ніхто не наважився ні на що, ні на підтримку моєї відповіді.

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

Я розумію, що JVM зазвичай знає краще за вас, коли йому потрібно повернути пам'ять. Я також розумію, що турбуватися про кілька кілобайт даних нерозумно. Я також розумію, що навіть мегабайт даних - це не те, що було кілька років тому. Але все-таки 1,5 гігабайта? І ви знаєте, що в пам’яті висить 1,5 ГБ даних; це не так, як це постріл у темряві. Є чи System.gc()систематично погано, або є якась - то точка , в якій вона стає добре?

Тож питання насправді подвійне:

  • Чому варто дзвонити чи не погана практика System.gc()? Це насправді просто натяк на JVM у певних реалізаціях, або це завжди повний цикл збору? Чи реально реалізуються сміттєзбірники, які можуть виконувати свою роботу, не зупиняючи світ? Будь ласка, пролийте трохи світла на різні твердження, які люди висловили у коментарях до моєї відповіді .
  • Де поріг? Це ніколи не годиться зателефонувати System.gc(), або є випадки, коли це прийнятно? Якщо так, то які часи?

4
Я думаю, що вдалий час для виклику System.gc () - це коли ви вже робите щось, що вже тривалий процес завантаження. Наприклад, я працюю над грою і планую зателефонувати System.gc (), коли гра завантажує новий рівень, наприкінці процесу завантаження. Користувач уже трохи чекає, і додаткове підвищення продуктивності може бути того варте; але я також розміщу опцію на екрані конфігурації, щоб відключити цю поведінку.
Ricket

41
Божо: зверніть увагу на перше слово запитання. ЧОМУ найкраща практика цього не називати? Просто повторення мантри не пояснює прокляту річ.
ДАЙТЕ МОЕ правильне ДУМКА

1
Інший випадок був пояснений у java-monitor.com/forum/showthread.php?t=188 Де пояснюється, як можна погано звикати викликати System.gc ()
Shirishkumar Bari

Відповіді:


243

Причина, по якій усі завжди кажуть уникати System.gc(), - це досить хороший показник принципово зламаного коду . Будь-який код, який від цього залежить від правильності, безумовно, порушений; будь-які, які покладаються на це для продуктивності, швидше за все, зламані.

Ви не знаєте, під яким збирачем сміття ви працюєте. Звичайно, є такі, які не «зупиняють світ», як ви стверджуєте, але деякі JVM не такі розумні, або з різних причин (можливо, вони є на телефоні?) Цього не роблять. Ви не знаєте, що це буде робити.

Також нічого не гарантовано робити. JVM може просто повністю ігнорувати ваш запит.

Поєднання "ти не знаєш, що це буде робити", "ти не знаєш, чи це навіть допоможе" і "вам не потрібно це називати все одно", чому люди настільки сильно говорять, що взагалі вам не слід це називати. Я думаю, що це випадок "якщо вам потрібно запитати, чи варто вам це використовувати, не варто"


EDIT, щоб вирішити кілька проблем з іншого потоку:

Після прочитання теми, яку ви пов’язали, я хотів би зазначити ще кілька речей. По-перше, хтось припустив, що дзвінки gc()можуть повернути пам'ять у систему. Це неодмінно вірно - сама купа Java росте незалежно від асигнувань Java.

Як і в, JVM буде утримувати пам'ять (багато десятків мегабайт) і вирощувати купу, якщо це необхідно. Це не обов'язково повертає цю пам'ять до системи, навіть коли ви звільняєте об'єкти Java; це абсолютно безкоштовно, щоб утримати виділену пам’ять, яку використовувати для майбутніх виділень Java.

Щоб показати, що можливо System.gc()нічого не робить, перегляньте:

http://bugs.sun.com/view_bug.do?bug_id=6668279

і, зокрема, що існує -XX: DisableExplicitGC VM.


1
Можливо, вам вдасться побудувати якусь дивну установку Rube Goldberg-esque, де метод, в якому запускається GC, впливає на правильність вашого коду. Можливо, це маскує якусь дивну взаємодію з потоками, або, можливо, фіналізатор має істотний вплив на роботу програми. Я не зовсім впевнений, що це можливо, але це може бути, тому я подумав, що це згадаю.
Стівен Шланскер

2
@zneak ви, наприклад, могли поставити критичний код у фіналізаторі (що принципово порушено код)
Мартін

3
Хочу додати, що є кілька кутових випадків, коли System.gc()це корисно і навіть може знадобитися. Наприклад, у програмах UI для Windows це може значно пришвидшити процес відновлення вікна під час виклику System.gc () перед тим, як мінімізувати вікно (особливо, коли воно залишається мінімізованим протягом досить тривалого часу, і частини процесу заміняються на диск).
Йоахім Зауер

2
@AndrewJanke Я б сказав, що код, який використовує WeakReferences для об'єктів, за які ви хочете тримати, є неправильним з самого початку, збирання сміття чи ні. У вас буде та сама проблема в C ++ з std::weak_ptr(хоча ви можете помітити проблему у версії C ++ раніше, ніж у версії Java, оскільки руйнування об'єкта не буде відкладено так, як це відбувається зазвичай).
JAB

2
@rebeccah Це помилка, так що так, я б назвав це "безумовно, зламаним". Те, що System.gc()виправляє це, є вирішенням, а не хорошою практикою кодування.
Стівен Шланскер

149

Вже було пояснено, що виклик system.gc() може нічого не робити, і будь-який код, який "потребує" сміттєзбірника, порушений.

Однак, прагматична причина, яку називати поганою практикою, System.gc()полягає в тому, що вона неефективна. І в гіршому випадку це жахливо неефективно ! Дозволь пояснити.

Типовий алгоритм GC ідентифікує сміття, обходячи всі об'єкти, що не є сміттями, і визначає, що будь-який не відвідуваний об'єкт повинен бути сміттям. Виходячи з цього, ми можемо моделювати загальну роботу зі збору сміття, що складається з однієї частини, пропорційної кількості живих даних, та іншої частини, пропорційної кількості сміття; тобто work = (live * W1 + garbage * W2).

Тепер припустимо, що ви робите наступне в однопотоковому додатку.

System.gc(); System.gc();

Перший дзвінок дозволить (ми прогнозуємо) виконати (live * W1 + garbage * W2)роботу та позбутися непотрібного сміття.

Другий дзвінок не (live* W1 + 0 * W2)спрацює і нічого не відшкодує. Іншими словами, ми зробили (live * W1)роботу і нічого не досягли .

Ми можемо моделювати ефективність роботи колектора як обсяг роботи, необхідний для збору одиниці сміття; тобто efficiency = (live * W1 + garbage * W2) / garbage. Отже, щоб зробити GC максимально ефективним, нам потрібно максимізувати значення, garbageколи ми запускаємо GC; тобто чекайте, поки купа заповниться. (А також зробіть купу якомога більшою. Але це окрема тема.)

Якщо програма не заважає (зателефонувавши System.gc()), GC зачекає, поки купа заповниться перед запуском, що призведе до ефективного збору сміття 1 . Але якщо додаток змусить GC працювати, шанси на те, що купа не буде повною, і результат буде, що сміття збирається неефективно. І чим частіше примушує застосування GC, тим більш неефективним стає GC.

Примітка: вище пояснення пояснюється тим, що типовий сучасний GC розділяє купу на "пробіли", GC може динамічно розширювати купу, робочий набір додатків, що не містять сміття, може змінюватись тощо. Незважаючи на це, той самий основний принцип застосовується на всіх рівнях до всіх справжніх збирачів сміття 2 . Примушувати ГК працювати неефективно.


1 - Так працює колектор "пропускної здатності". Одночасно збирачі сміття, такі як CMS та G1, використовують різні критерії, щоб вирішити, коли запустити сміттєзбірник.

2 - Я також виключаю менеджери пам'яті, які використовують виключно підрахунок посилань, але жодна поточна реалізація Java не використовує цей підхід ... з поважної причини.


45
+1 Добре пояснення. Однак зауважте, що це міркування застосовується лише в тому випадку, якщо ви дбаєте про пропускну здатність. Якщо ви хочете оптимізувати латентність у певних точках, форсування GC може мати сенс. Напр. (Гіпотетично кажучи) у грі, можливо, ви хочете уникнути затримок під час рівнів, але вас не хвилює затримка під час завантаження рівня. Тоді було б сенс застосовувати GC після навантаження рівня. Це зменшує загальну пропускну здатність, але це не те, що ви оптимізуєте.
sleske

2
@sleske - те, що ти кажеш, є правдою. Однак, запуск GC між рівнями є рішенням про допомогу в діапазоні ... і не вирішує проблеми із затримкою, якщо рівні триватимуть досить довго, що вам потрібно все-таки запустити GC під час рівня. Кращим підходом є використання одночасного (низької паузи) сміттєзбірника ... якщо платформа підтримує це.
Стівен C

Не зовсім впевнений, що ви маєте на увазі під "необхідністю роботи сміттєзбірника". Умови, яких необхідно уникати, заявок; невдачі в розподілі, які ніколи не можуть бути задоволені, і високі витрати на загальний рівень GC. Випадково дзвінки до System.gc () часто призводять до великих накладних витрат.
Кірк

@Kirk - "Випадкові виклики до System.gc () часто призводять до високих накладних витрат GC." . Я це знаю. Так би і кожен, хто прочитав і зрозумів мою відповідь.
Стівен C

@Kirk - "Не зовсім впевнений, що ти маєш на увазі ..." - я маю на увазі програми, де "правильна" поведінка програми залежить від роботи GC у певний час; наприклад, щоб виконати фіналізатори, або зламати слабкі референції або SoftReferences. Це дійсно погана ідея зробити це ... але про це я говорю. Дивіться також відповідь Стівена Шланскера.
Стівен C

47

Багато людей, здається, говорять вам не робити цього. Я не погоджуюсь. Якщо після великого процесу завантаження, наприклад завантаження рівня, ви вважаєте, що:

  1. У вас багато об’єктів, недоступних і, можливо, не були gc'ed. і
  2. Ви думаєте, що користувач може миритися з невеликим уповільненням в цей момент

немає шкоди для виклику System.gc (). Я дивлюся на це як inlineключове слово c / c ++ . Це лише натяк на gc про те, що ви, розробник, вирішили, що час / продуктивність не так важливий, як це зазвичай, і що деякі з них можуть використовуватися для повернення пам'яті.

Порада не покладатися на це, роблячи щось, є правильним. Не покладайтеся на те, що це працює, але давати натяк на те, що зараз - прийнятний час для збору, - це зовсім чудово. Я вважаю за краще витрачати час на точку в коді, де це не має значення (екран завантаження), ніж коли користувач активно взаємодіє з програмою (наприклад, під час рівня гри.)

Буде один раз, коли я змушувати колекцію: коли я намагаюся дізнатись, чи протікає конкретний об'єкт (або власний код, або велика, складна взаємодія зворотного виклику. О, і будь-який компонент інтерфейсу, який так сильно дивиться на Matlab.) Це ніколи не слід використовувати у виробничому коді.


3
+1 для GC під час аналізу витоків пам’яті. Зауважте, що інформація про використання купи (Runtime.freeMemory () та ін.) Дійсно має значення лише після форсування GC, інакше це залежатиме від того, коли система востаннє заважала запускати GC.
sleske

4
Немає шкоди для виклику System.gc (), можливо, це вимагатиме stop the worldпідходу, і це справжня шкода, якщо це станеться
bestsss

7
Там є шкода в виклику збирача сміття в явному вигляді. Виклик GC в неправильний час витрачає цикли процесора. Ви (програміст) не маєте достатньо інформації, щоб визначити, коли настає правильний час ... але JVM має.
Стівен C

Після запуску Jetty здійснює 2 виклики до System.gc (), і я рідко бачив, щоб це мало значення.
Кірк

Ну, у розробників Jetty є помилка. Це мало б значення ... навіть якщо різницю важко оцінити.
Стівен C

31

Люди робили гарну роботу, пояснюючи, чому НЕ використовувати, тому я розповім вам кілька ситуацій, коли вам слід скористатися цим:

(Наступні коментарі стосуються Hotspot, що працює на Linux із колекціонером CMS, де я впевнено кажу, що System.gc()насправді завжди викликає повне збирання сміття).

  1. Після первинної роботи із запуску програми, у вас може виникнути жахливий стан використання пам'яті. Половина вашого покоління, яке перебуває у стані служби, може бути повноцінним сміттям, це означає, що ви настільки ближче до своєї першої CMS. У додатках, де це має значення, не погано закликати System.gc () "скинути" купу до початкового стану живих даних.

  2. У той же самий рядок, що і №1, якщо ви уважно стежите за використанням вашої купки, ви хочете точно прочитати, яким є використання вашої базової пам'яті. Якщо перші 2 хвилини тривалості роботи вашої програми - це все ініціалізація, ваші дані будуть змішані, якщо ви не змусите (ах ... "запропонувати") повний gc вперед.

  3. У вас може бути додаток, розроблений так, щоб ніколи нічого не рекламувати підрядчикові під час роботи. Але, можливо, вам потрібно ініціалізувати деякі дані наперед, які не такі вже й величезні, щоб автоматично переходити до штатного покоління. Якщо ви не зателефонуєте System.gc () після того, як все буде налаштовано, ваші дані можуть перебувати в новому поколінні, поки не настане час для просування по службі. Раптом ваше супер-пупер із низьким рівнем затримки з низьким вмістом GC потрапляє до ВЕЛИЧЕЗНОГО (відносно кажучи, звичайно) затримки за просування цих об'єктів під час звичайних операцій.

  4. Іноді корисно мати виклик System.gc у виробничому додатку для перевірки наявності витоку пам'яті. Якщо ви знаєте, що набір живих даних у часі X повинен існувати у певному співвідношенні до набору даних, що живуть у реальному часі Y, тоді може бути корисним назвати System.gc () час X та час Y та порівняти використання пам'яті .


1
Для більшості поколінь, що збирають сміття, об’єкти нового покоління повинні пережити певну (часто налаштовувану) кількість сміттєзбірників, тому заклик System.gc()одного разу до примусового просування об’єктів не приносить вам нічого. І ви, звичайно, не хочете телефонувати System.gc()вісім разів поспіль і моліться про те, щоб зараз просування було зроблено, а заощаджені витрати на більш пізню акцію виправдовують витрати на кілька повних ГК. Залежно від алгоритму GC, просування багатьох об'єктів може навіть не нести фактичних витрат, оскільки воно просто переукладе пам'ять старому поколінню або одночасно копіюватиме…
Holger

11

Це дуже набридливе питання, і я думаю, що сприяє тому, що багато хто виступає проти Java, незважаючи на те, наскільки корисною є мова.

Те, що ви не можете довіряти "System.gc" робити що-небудь, неймовірно нелегко і може легко викликати почуття мови "Страх, невпевненість, сумніви".

У багатьох випадках приємно мати справу з шипами пам’яті, які ви завдаєте навмисно до того, як відбудеться важлива подія, яка змусить користувачів вважати, що ваша програма погано розроблена / не відповідає.

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

Дозвольте переглянути аргументи цієї теми.

  1. Це неефективно:

Часто програма може нічого не робити, і ви знаєте, що нічого не роблять через те, як вона була розроблена. Наприклад, це може робити якесь довге очікування з великим полем очікування повідомлення, і наприкінці він може також додати дзвінок для збору сміття, оскільки час його запуску займе дійсно невелику частину часу довго чекати, але уникнути дії gc в середині більш важливої ​​операції.

  1. Це завжди погана практика і вказує на зламаний код.

Я не згоден, не має значення, який у вас смітник. Його робота - відстежувати сміття та прибирати його.

Викликаючи gc під час, коли використання менш критичне, ви зменшуєте шанси на його виконання, коли ваше життя покладається на певний код, який виконується, але натомість він вирішує збирати сміття.

Звичайно, це може поводитись не так, як ви хочете чи очікуєте, але коли ви хочете зателефонувати, ви знаєте, що нічого не відбувається, і користувач готовий терпіти повільність / простої. Якщо System.gc працює, чудово! Якщо не виходить, принаймні ви спробували. Тут просто немає сторони, якщо у сміттєзбірника немає притаманних побічних ефектів, які роблять щось жахливо несподіване для того, як збирач сміття повинен вести себе, якщо викликати його вручну, і це саме по собі викликає недовіру.

  1. Це не звичайний випадок використання:

Це випадок використання, який неможливо досягти надійно, але це може бути, якби система була спроектована таким чином. Це як зробити світлофор і зробити так, що деякі / всі кнопки світлофорів нічого не роблять, це змушує вас запитати, чому ця кнопка починається з того, що у JavaScript немає функції збору сміття, тому ми не Не вивчайте його настільки, наскільки це.

  1. Спеціалізація говорить, що System.gc () - це натяк на те, що GC має працювати, і VM може ігнорувати це.

що таке "підказка"? що таке "ігнорування"? комп'ютер не може просто приймати підказки або щось ігнорувати, існують суворі шляхи поведінки, які можуть бути динамічними, керуючись намірами системи. Правильна відповідь містила б те, що насправді робить сміттєзбірник на рівні впровадження, що призводить до того, що він не виконує збір, коли ви його запитуєте. Чи є функція просто nop? Чи є якісь умови, які мені повинні відповідати? Які ці умови?

Як відомо, GC Java часто здається монстром, якому ви просто не довіряєте. Ви не знаєте, коли це прийде чи піде, ви не знаєте, що це буде робити, як це робити. Я можу собі уявити, що деякі фахівці мають краще уявлення про те, як працює їх сміттєзбірник за інструкцією, але переважна більшість просто сподівається, що це "просто працює", і довіряти непрозорому алгоритму, який може працювати для вас, неприємно.

Існує великий розрив між читанням про щось або навчанням чогось, і власне баченням його реалізації, відмінностями між системами та можливістю грати з ним, не дивлячись на вихідний код. Це створює впевненість і відчуття майстерності / розуміння / контролю.

Підводячи підсумок, існує відповідна проблема з відповідями: "Ця функція може нічого не робити, і я не буду вникати в деталі, як сказати, коли вона щось робить, а коли - ні, і чому це не буде чи буде, часто маючи на увазі, що намагатися зробити це просто проти філософії, навіть якщо наміри за нею є розумними ".

Для Java GC може бути добре поводитись так, як це робиться, а може і ні, але зрозуміти це, важко по-справжньому слідувати, в якому напрямку рухатися, щоб отримати всебічний огляд того, що можна довіряти GC та робити не робити цього, тому занадто просто просто недовіряти мові, адже мета мови - це керувати поведінкою до філософської міри (програмісту, особливо новачкам, впасти в екзистенційну кризу з певної поведінки системи / мови) ви здатні терпіти (і якщо ви не можете, ви просто не будете користуватися мовою, поки не доведеться), і більше речей, якими ви не можете керувати, з невідомих причин, чому ви не можете керувати ними, за своєю суттю шкідливо.


9

Ефективність GC спирається на ряд евристики. Наприклад, поширеним евристичним є те, що звернення до записів до об'єктів зазвичай відбувається на об'єктах, створених недавно. Інша полягає в тому, що багато об’єктів дуже недовговічні (деякі об’єкти будуть використовуватися протягом тривалого часу, але багато людей будуть відкинуті через кілька мікросекунд після їх створення).

Телефонувати System.gc()- це як бити ГК. Це означає: "усі ті ретельно налаштовані параметри, ті розумні організації, всі зусилля, які ви тільки що доклали до розподілу та управління об'єктами, щоб все пройшло гладко, ну просто киньте всю партію і почніть з нуля". Це може покращити продуктивність, але більшість часу це просто погіршує продуктивність.

Щоб System.gc()надійно використовувати (*), ви повинні знати, як працює GC у всіх її тонких деталях. Такі деталі, як правило, досить сильно змінюються, якщо ви використовуєте JVM від іншого постачальника, або наступну версію від того ж постачальника, або той самий JVM, але з дещо різними параметрами командного рядка. Тому рідко буває корисною ідеєю, якщо ви не хочете вирішити певну проблему, в якій ви контролюєте всі ці параметри. Звідси і поняття «погана практика»: це не заборонено, метод існує, але він рідко окупається.

(*) Я говорю тут про ефективність. System.gc()ніколи не порушить правильну програму Java. Це не спричинить додаткової пам’яті, яку JVM не міг отримати інакше: перед тим, як кинути OutOfMemoryError, JVM виконує цю роботу System.gc(), навіть як в крайньому випадку.


1
+1 за згадку про те, що System.gc () не заважає OutOfMemoryError. Деякі люди вірять у це.
sleske

1
Насправді це може запобігти OutOfMemoryError через обробку м'яких посилань. SoftReferences, створені після останнього запуску GC, не збираються у реалізацію, яку я знаю. Але це детальна інформація про впровадження, яка може змінюватися в будь-який час і своєрідна помилка, і нічого, на що слід покладатися.
maaartinus

8

Іноді ( не часто! ) Ви справді знаєте більше про минуле, поточне та майбутнє використання пам’яті, ніж час роботи. Це трапляється не дуже часто, і я б не стверджував, що ніколи у веб-додатку, поки звичайні сторінки подаються.

Багато років тому я працюю над генератором звітів, що

  • Мав єдину нитку
  • Прочитайте "запит на звіт" з черги
  • Завантажували дані, необхідні для звіту, із бази даних
  • Створили звіт та надіслали його електронною поштою.
  • Повторювався назавжди, спав, коли не було невирішених прохань.
  • Він не використовував жодних даних між звітами та не здійснював готівку.

По-перше, оскільки це було не в реальному часі, і користувачі очікували чекати звіту, затримка під час запуску GC не була проблемою, але нам потрібно було складати звіти швидкістю, ніж вони вимагали.

Поглянувши на вищезазначені контури процесу, зрозуміло, що.

  • Ми знаємо, що живих об’єктів було б дуже мало відразу після надсилання звіту, оскільки наступний запит ще не почався обробкою.
  • Добре відомо, що вартість запуску циклу вивезення сміття залежить від кількості живих об'єктів, кількість сміття мало впливає на вартість запуску GC.
  • Якщо у черзі порожньо немає нічого кращого, ніж запустити GC.

Тому, очевидно, варто було виконати запуск GC кожного разу, коли черга запиту була порожньою; Не було недоліків у цьому.

Можливо, варто зробити запуск GC після надсилання кожного звіту, оскільки ми знаємо, що це час для запуску програми GC. Однак якби на комп'ютері було достатньо оперативної пам’яті, кращі результати були б отримані, затримуючи пробіг GC.

Така поведінка була налаштована на основі встановлення за кожним замовленням, для деяких клієнтів вмикався примусовий GC після кожного звіту значно прискорювали захист звітів. (Я очікую, що це було пов’язано з низькою пам’яттю на їх сервері, і він працює безліч інших процесів, тому, зважаючи на те, що час GC змушене скорочувати пейджинг)

Ми ніколи не виявляли, що установка, яка не принесла користі, - це був примусовий запуск GC кожного разу, коли робоча черга була порожньою.

Але, нехай буде зрозуміло, вищесказане не є звичайною справою.


3

Можливо, я пишу безладний код, але я зрозумів, що натискання піктограми кошика на IDEs затемнення та мереж - це «хороша практика».


1
Це може бути так. Але якби Eclipse або NetBeans були запрограмовані System.gc()періодично телефонувати , ви, мабуть, виявили б поведінку дратівливою.
Стівен C

2

По-перше, існує різниця між специфікацією та реальністю. Спеціалізація говорить, що System.gc () - це натяк на те, що GC має працювати, і VM може ігнорувати це. Реальність полягає в тому, що VM ніколи не ігнорує виклик System.gc ().

Виклик GC має нетривіальний накладний виклик, і якщо ви зробите це в якийсь випадковий момент часу, швидше за все, ви не побачите нагороди за свої зусилля. З іншого боку, швидше за все, природне спрацьовування колекції компенсує витрати на дзвінок. Якщо у вас є інформація, яка вказує на те, що GC повинен бути запущений, ніж ви можете зателефонувати на System.gc (), і ви побачите переваги. Однак, на моєму досвіді, це трапляється лише в декількох крайніх випадках, оскільки це малоймовірно, що у вас буде достатньо інформації, щоб зрозуміти, чи потрібно і коли викликати System.gc ().

Один з наведених тут прикладів, потрапляючи на смітник у вашому IDE. Якщо ви їдете на зустріч, чому б не вдарити її. Накладні витрати не вплинуть на вас, і купа може бути очищена, коли ви повернетесь. Зробіть це у виробничій системі і часті дзвінки про збирання призведуть до затоплення! Навіть випадкові дзвінки, такі як дзвінки RMI, можуть бути руйнівними для продуктивності.


3
"Реальність полягає в тому, що VM ніколи не ігнорує виклик System.gc ()." - Неправильно. Читайте про -XX: -DisableExplicitGC.
Стівен C

1

Так, виклик System.gc () не гарантує його запуск, це може бути ігноровано запит до JVM. З документів:

Виклик методу gc передбачає, що віртуальна машина Java витрачає зусилля на переробку невикористаних об'єктів

Це майже завжди погана ідея називати це, тому що автоматичне управління пам’яттю зазвичай знає краще, ніж ви, коли потрібно працювати. Це буде зроблено, коли внутрішній пул вільної пам’яті низький або якщо ОС вимагає повернути деяку пам’ять.

Якщо ви знаєте, що це допомагає, можна зателефонувати на System.gc () . Я маю на увазі, що ви ретельно перевірили та виміряли поведінку обох сценаріїв на платформі розгортання , і ви можете показати, що це допомагає. Будьте в курсі, що gc - це нелегко передбачувано - це може допомогти за один пробіг і пошкодити інший.


<stroke> Але також з Javadoc: _Колі управління повертається з виклику методу, віртуальна машина доклала максимум зусиль, щоб переробити всі відкинуті об'єкти, що я вважаю більш імперативною формою того, що ви розмістили. </ stroke > Накрутіть це, є повідомлення про помилку про його введення в оману. Як відомо, хто краще знає, які шкоди натякають на СП?
zneak

1
Шкода полягає в тому, що робити колекцію в невідповідний час може величезне сповільнення. Підказка, яку ви даєте, ймовірно, погана. Що стосується коментаря "найкращі зусилля", спробуйте його та перегляньте такий інструмент, як JConsole. Іноді , натиснувши на кнопку «Виконати» GC нічого не робить
Том

Вибачте, не погоджуючись, але виклик System.gc () у OpenJDK і все, що базується на ньому (наприклад, HP), завжди призводить до циклу вивезення сміття. Насправді це також відповідає дійсності впровадження IBM J9
Кірк,

@Kirk - Неправильно: google та читати про -XX: -DisableExplicitGC.
Стівен C

0

На мій досвід, використання System.gc () є ефективно платформовою формою оптимізації (де "платформа" - це поєднання архітектури обладнання, ОС, версії JVM та можливих інших параметрів виконання, таких як оперативна пам'ять), тому що її поведінка, хоча приблизно передбачувано на певній платформі, може (і буде) значно відрізнятися між платформами.

Так, бувають ситуації, коли System.gc () покращить (сприйнять) продуктивність. Наприклад, якщо затримки допустимі в деяких частинах вашої програми, а не в інших (приклад прикладу гри, цитований вище, де ви хочете, щоб GC відбувався на початку рівня, а не під час рівня).

Однак, чи допоможе це чи зашкодить (чи нічого не робити), дуже залежить від платформи (як визначено вище).

Тому я вважаю, що це справедливо як оптимізація, що стосується крайньої платформи (тобто якщо інших оптимізацій ефективності недостатньо). Але ніколи не слід називати це лише тому, що ви вважаєте, що це може допомогти (без конкретних орієнтирів), тому що, швидше за все, це не буде.


0
  1. Оскільки об'єкти динамічно розподіляються за допомогою нового оператора,
    вам може бути цікаво, як такі об’єкти знищуються та їх
    пам'ять звільняється для подальшого перерозподілу.

  2. У деяких мовах, таких як C ++, динамічно виділені об'єкти повинні бути звільнені вручну за допомогою оператора видалення.

  3. Java застосовує інший підхід; він обробляє розсилку для вас автоматично.
  4. Техніка, яка це досягає, називається вивезенням сміття. Це працює так: коли ніяких посилань на об'єкт не існує, цей об'єкт вважається більше не потрібним, і пам'ять, яку займає об'єкт, може бути відновлена. Немає явної необхідності знищувати об'єкти, як у C ++.
  5. Збір сміття відбувається лише епізодично (якщо він взагалі є) під час виконання вашої програми.
  6. Це не відбудеться просто тому, що існує один або більше об'єктів, які вже не використовуються.
  7. Крім того, різні впровадження Java-програми будуть використовувати різні підходи до збору сміття, але здебільшого вам не доведеться думати про це під час написання програм.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.