Збірка сміття і метод finalize

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

Простіше кажучи, це означає, що память, займана невживаних обєктом, може бути повернута в систему При цьому ніяких дій з вашого боку не потрібно – по суті, ви нічого і не зможете зробити Обєкт є невживаних, коли на нього відсутні посилання в статичних даних і в будь-який з змінних

виконуваного зараз методу, коли не вдається знайти посилання на нього за допомогою відстеження полів і елементів масивів статичних даних і змінних методів, і так далі Обєкти створюються оператором new, але відповідного йому оператора delete не існує Після завершення роботи з обєктом ви просто перестаєте посилатися на нього (змінюєте його посилання так, щоб вона вказувала на інший обєкт або null) або повертаєтеся з методу, щоб його локальні змінні перестали існувати і не вказували на обєкт Коли посилань на обєкт не залишається ніде, за винятком інших невикористовуваних обєктів, даний обєкт може бути знищений складальником сміття Ми користуємося виразом може бути, тому що память звільняється лише в тому випадку, якщо її недостатньо або якщо збирач сміття захоче запобігти її нестачу

Автоматична збірка сміття означає, що вам ніколи не доведеться турбуватися про проблему завислих посилань (dangling references) У тих системах, де передбачений прямий контроль за видаленням, допускається звільнення обєктів, на які посилаються інші обєкти У такому випадку посилання стає зависла, тобто вона вказує на область памяті, яка в системі вважається вільною Ця вільна память може бути використана для створення нового обєкта, і тоді зависла посилання вказуватиме на щось зовсім відмінне від того, що передбачалося в обєкті У результаті вміст цієї памяті може бути використано абсолютно непередбачуваним чином, і виникає повний хаос Java вирішує проблему завислих посилань за вас, оскільки обєкт, на який є посилання, ніколи не буде знищений складальником сміття

Збірка сміття відбувається без вашого втручання, проте вона все ж вимагає певної уваги Створення і знищення численних обєктів може перешкодити роботі тих додатків, для яких час виконання виявляється критичним Програми слід проектувати так, щоб кількість створюваних в них обєктів було розумним

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

2101 Метод finalize

Зазвичай ви і не помічаєте, як відбувається знищення осиротілих обєктів Проте клас може реалізувати метод з імям finalize, який виконується перед знищенням обєкта або при завершенні роботи віртуальної машини Метод finalize дає можливість використовувати видалення обєкта для звільнення інших, не повязаних з Java ресурсів Він оголошується таким чином:

protected void finalize() throws Throwable {

superfinalize()

// ..

}

Роль методу finalize стає особливо суттєвою при роботі з зовнішніми стосовно Java ресурсами, які занадто важливі, щоб можна було чекати етапу збірки сміття Наприклад, відкриті файли (Число яких зазвичай обмежена) не можуть чекати завершальної фази finalize – немає ніякої гарантії, що обєкт, що містить відкритий файл, буде знищений складальником сміття до того, як витратяться всі ресурси з відкриття файлів

Тому в обєкти, що розпоряджаються зовнішніми ресурсами, слід включати метод finalize, що звільняє ресурси і запобігає їх відплив Крім того, вам доведеться надати програмістам можливість явного звільнення цих ресурсів Наприклад, в клас, який відкриває файл для своїх цілей, слід включити метод close для закриття файлу, щоб користуються цим класом програмісти могли явним чином розпоряджатися кількістю відкритих файлів в системі

Іноді може статися так, що метод close НЕ буде викликаний, незважаючи на те, що робота з обєктом закінчена Можливо, вам уже доводилося стикатися з подібними випадками Ви можете частково запобігти Витік файлів, включивши в клас метод finalize, усередині якого викликається close, – таким чином можна бути впевненим, що незалежно від якості роботи інших програмістів ваш клас ніколи не поглинатиме відкриті файли Ось як це може виглядати на практиці:

public class ProcessFile {

private Stream File

public ProcessFile(String path) { File = new Stream(path)

}

// ..

public void close() {

if (File = null) { Fileclose() File = null

}

}

protected void finalize() throws Throwable {

superfinalize()

close()

}

}

Зверніть увагу: метод close написаний так, щоб його можна було викликати кілька разів В іншому випадку, якби метод close вже використовувався раніше, то при виклику finalize відбувалася б спроба повторного закриття файлу, що може призвести до помилок

Крім того, у наведеному вище прикладі слід звернути увагу на те, що метод finalize викликає superfinalize Нехай це увійде у вас у звичку для всіх методів finalize, які вам доведеться писати Якщо не використовувати superfinalize, то робота вашого класу завершиться нормально, але суперкласу, для яких не були виконані необхідні завершальні дії, можуть викликати збої Памятайте, виклик superfinalize – Це корисне правило, застосовується навіть у тому випадку, якщо ваш клас не є розширенням іншого класу Крім того, що це послужить вам додатковим

нагадуванням на майбутнє, виклик superfinalize в подібних ситуаціях дозволить у майбутньому породити клас, аналогічний Process File, від іншого суперкласу і при цьому не

піклуватися про переробку методу finalize

У тілі методу finalize може застосовуватися конструкція try / catch для обробки виключень в викликаються методах, але будь-які неперехваченние виключення, що виникли при виконанні методу finalize, ігноруються Винятки детально розглядаються в розділі 7

Збирач сміття може знищувати обєкти в будь-якому порядку, а може і не знищувати їх зовсім Память буде звільнятися в той момент, який збирач сміття вважатиме підходящим Відсутність привязки до якогось конкретному порядку дозволяє збирачеві

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

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

2102 Відновлення обєктів у методі

Метод finalize може воскресити обєкт, знову роблячи його використовуваним – скажімо, включаючи його в статичний список обєктів Подібні дії не рекомендуються, але Java не зможе нічого зробити, щоб запобігти їх

Проте Java викликає finalize рівно один раз для кожного обєкта, навіть якщо даний обєкт знищується складальником сміття повторно через те, що він був відновлений в попередньому виклику finalize Якщо подібне відновлення обєктів виявляється важливим для концепції вашої програми, то відбуватися воно буде всього один раз – малоймовірно, щоб ви домагалися від програми саме такої поведінки

Якщо ви дійсно вважаєте, що вам необхідно відновлювати обєкти, спробуйте ретельно переглянути свою програму – можливо, ви виявите в ній якісь недоліки Якщо ж і після цього ви впевнені, що без відновлення обєктів ніяк не обійтися, то правильним рішенням буде дублювання або створення нового обєкта, а не відновлення Метод finalize може створити посилання на новий обєкт, стан якого збігається зі станом знищуваного обєкта Так як дубльований обєкт створюється заново, при необхідності в майбутньому може бути викликаний його метод finalize, який помістить ще одну копію обєкта в який-небудь інший список – це забезпечить виживання якщо не самого обєкта, то його точної копії

Джерело: Арнольд К, Гослінг Д – Мова програмування Java (1997)

Схожі статті:


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

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*