Чи існує спосіб звільнення пам'яті на Java, схожий на free()
функцію C ? Або встановлення об’єкта на нуль і покладання на GC єдиний варіант?
Чи існує спосіб звільнення пам'яті на Java, схожий на free()
функцію C ? Або встановлення об’єкта на нуль і покладання на GC єдиний варіант?
Відповіді:
Java використовує керовану пам'ять, тому єдиний спосіб розподілити пам'ять - це за допомогою new
оператора, і єдиний спосіб розподілити пам'ять - це покладатися на смітник.
Цей документ про управління пам'яттю (PDF) може допомогти пояснити, що відбувається.
Ви також можете зателефонувати, System.gc()
щоб запропонувати негайно запустити сміттєзбірник. Однак, Java Runtime приймає остаточне рішення, а не ваш код.
Згідно з документацією на Java ,
Виклик методу gc передбачає, що віртуальна машина Java витрачає зусилля на переробку невикористаних об'єктів, щоб зробити пам'ять, яку вони зараз займають, доступною для швидкого використання. Коли управління повертається з виклику методу, віртуальна машина Java доклала максимум зусиль, щоб повернути простір з усіх викинутих об'єктів.
System.gc()
повністю ігнорують .
Здається, ніхто не згадував прямо встановлення посилань на об'єкти null
, що є законною методикою "звільнення" пам'яті, яку ви можете розглянути.
Наприклад, скажіть, що ви оголосили, що ви List<String>
на початку використовували метод, який збільшився в дуже великому розмірі, але його потрібно було лише на півдорозі. Ви можете в цей момент встановити посилання на Списокnull
щоб дозволити сміттєзбірнику повернути цей об'єкт до завершення методу (і посилання все одно не виходить із сфери застосування).
Зауважте, що я дуже рідко використовую цю техніку в реальності, але це варто враховувати, коли ми маємо справу з дуже великими структурами даних.
System.gc();
Працює сміттєзбірник.
Виклик методу gc передбачає, що віртуальна машина Java витрачає зусилля на переробку невикористаних об'єктів, щоб зробити пам'ять, яку вони зараз займають, доступною для швидкого використання. Коли управління повертається з виклику методу, віртуальна машина Java доклала максимум зусиль, щоб повернути простір з усіх викинутих об'єктів.
Не рекомендовано.
Редагувати: Оригінальну відповідь я написав у 2009 році. Зараз це 2015 рік.
Сміттєзбірники ставали все краще в останні 20 років. У цей момент, якщо ви вручну викликаєте сміттєзбірник, можливо, ви захочете розглянути інші підходи:
* "Я особисто покладаюся на нульові змінні як заповнювач для майбутнього належного видалення. Наприклад, я беру час, щоб звести нанівець всі елементи масиву, перш ніж насправді видалити (зробити нуль) самого масиву."
Це зайве. Спосіб роботи Java GC полягає в тому, що він знаходить об'єкти, на які немає посилання на них, тому якщо у мене є Object x із посиланням (= змінною) a, який вказує на нього, GC не видалить його, оскільки є посилання до цього об'єкта:
a -> x
Якщо ви маєте нульове значення a, це відбувається:
a -> null
x
Отже, x не має посилання на нього і буде видалено. Те ж саме відбувається, коли ви встановлюєте посилання на інший об'єкт, ніж x.
Отже, якщо у вас є масив масиву, який посилається на об'єкти x, y і z, і змінна a, що посилається на масив, виглядає так:
a -> arr -> x
-> y
-> z
Якщо ви маєте нульове значення a, це відбувається:
a -> null
arr -> x
-> y
-> z
Таким чином, GC знаходить arr як відсутність посилань на нього та видаляє, що дає вам цю структуру:
a -> null
x
y
z
Тепер GC знаходить x, y і z і видаляє їх також. Зміна кожної посилання в масиві не покращить нічого, воно просто використовуватиме час та простір CPU у коді (що сказало, це не зашкодить далі. GC все одно зможе виконати так, як слід ).
Вагомою причиною бажання звільнити пам'ять від будь-якої програми (java чи ні) є надання більшої кількості пам'яті для інших програм на рівні операційної системи. Якщо у моїй програмі Java використовується 250 МБ, я, можливо, захочу примусити її до 1 МБ та зробити доступним 249 МБ для інших програм.
Щоб продовжити відповідь та коментар Yiannis Xanthopoulos та Hot Licks (вибачте, я поки не можу прокоментувати!), Ви можете встановити такі параметри VM, як цей приклад:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
У моєму jdk 7 це дозволить випустити невикористану пам'ять VM, якщо більше 30% купи стане вільним після GC, коли VM не працює. Можливо, вам доведеться налаштувати ці параметри.
Хоча я не бачив цього підкресленим у посиланні нижче, зауважте, що деякі сміттєзбірники можуть не підкорятися цим параметрам, і за замовчуванням Java може вибрати один із них, якщо у вас є більше одного ядра (звідси аргумент UseG1GC вище ).
Оновлення: для java 1.8.0_73 Я бачив, що JVM періодично випускає невеликі суми з налаштуваннями за замовчуванням. Здається, це робити лише в тому випадку, коли ~ 70% купи не використовується, не знаю, чи було б більш агресивним вивільненням, якби ОС мала на фізичній пам'яті.
Я зробив експерименти над цим.
Це правда, що System.gc();
лише пропонує запустити смітник.
Але виклик System.gc();
після встановлення всіх посилань на null
поліпшить продуктивність та зайнятість пам’яті.
Якщо ви дійсно хочете виділити та звільнити блок пам’яті, ви можете зробити це за допомогою прямих ByteBuffers. Існує навіть непортативний спосіб звільнити пам'ять.
Однак, як було запропоновано, саме те, що вам потрібно звільнити пам'ять на C, не означає, що це не годиться.
Якщо ви вважаєте, що у вас є справжній випадок корисного використання безкоштовно (), будь ласка, включіть його у запитання, щоб ми побачили, що ви ртуєтеся робити, цілком ймовірно, що є кращий спосіб.
Цілком із javacoffeebreak.com/faq/faq0012.html
Нитка з низьким пріоритетом автоматично бере на себе збирання сміття для користувача. Під час простою може зателефонувати потік, і він може почати звільняти пам'ять, попередньо виділену об'єкту на Java. Але не хвилюйтесь - це не видалить ваші об’єкти!
Коли немає ніяких посилань на об'єкт, це стає справедливою грою для сміттєзбірника. Замість того, щоб викликати якусь рутину (наприклад, безкоштовно в C ++), ви просто призначите всі посилання на об’єкт нульовими або призначите новий клас посиланню.
Приклад:
public static void main(String args[]) { // Instantiate a large memory using class MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192); // Do some work for ( .............. ) { // Do some processing on myClass } // Clear reference to myClass myClass = null; // Continue processing, safe in the knowledge // that the garbage collector will reclaim myClass }
Якщо ваш код збирається запросити великий об'єм пам'яті, ви можете попросити сміттєзбірник почати відбирати місце, а не дозволяти йому робити це як нитка з низьким пріоритетом. Для цього додайте у свій код наступне
System.gc();
Збирач сміття спробує повернути вільний простір, і ваш додаток може продовжувати виконувати з якомога більшою кількістю пам'яті (проблеми з фрагментацією пам'яті можуть застосовуватися на певних платформах).
У моєму випадку, оскільки мій код Java передбачається перенести на інші мови найближчим часом (головним чином на C ++), я, принаймні, хочу платити послугу для вивільнення пам'яті належним чином, щоб це допомагало згодом процес перенесення.
Я особисто покладаюся на нульові змінні як заповнювач для майбутнього належного видалення. Наприклад, я потребую часу, щоб звести нанівець всі елементи масиву, перш ніж насправді видалити (зробити нуль) самого масиву.
Але мій випадок дуже особливий, і я знаю, що роблю хіти, коли я роблю це.
* "Наприклад, скажіть, що ви оголосили" Список "на початку методу, який збільшився в розмірі, щоб бути дуже великим, але його потрібно було лише до початку шляху. Ви можете в цей момент встановити посилання списку на null щоб дозволити колектору сміття потенційно повернути цей об’єкт до завершення методу (і посилання все одно виходить із сфери застосування). " *
Це правильно, але це рішення може бути не узагальненим. Під час встановлення посилання об'єкта List на null -will- зробить пам'ять доступною для збору сміття, це справедливо лише для об'єкта List примітивних типів. Якщо натомість об'єкт List містить типи посилань, встановлення об'єкта List = null не буде перенаправляти -any- з посилальних типів, що містяться -in- списку. У цьому випадку встановлення об'єкта List = null осиротить містять посилання типи, об’єкти яких не будуть доступні для вивезення сміття, якщо алгоритм збору сміття не є достатньо розумним, щоб визначити, що об'єкти осиротіли.
Через Java передбачено автоматичне збирання сміття; іноді вам потрібно буде знати, наскільки великий об’єкт і скільки на нього залишилося. Безкоштовна пам'ять, використовуючи програмно, import java.lang;
і Runtime r=Runtime.getRuntime();
отримувати значення пам'яті, використовуючи метод mem1=r.freeMemory();
виклику пам'яті r.gc();
та викликfreeMemory()
Рекомендація від JAVA - присвоїти null
Від https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
Явне призначення нульового значення змінним, які більше не потрібні, допомагає сміттєзбірнику визначити частини пам'яті, які можуть бути безпечно відшкодовані. Хоча Java забезпечує управління пам'яттю, це не запобігає витоку пам'яті або використанню надмірної кількості пам'яті.
Додаток може викликати протікання пам'яті, не випускаючи посилання на об'єкт. Це запобігає поверненню Java-сміттєзбірника цих об'єктів і призводить до збільшення кількості пам'яті. Явно зводить нанівець посилання на змінні після їх використання дозволяє сміттєзбірнику відновлювати пам'ять.
Один із способів виявити витоки пам’яті - використовувати інструменти профілювання та робити знімки пам’яті після кожної транзакції. Додаток без витоку в стаціонарному стані покаже стійку активну пам’ять після збирання сміття.