Яка різниця між java.lang.ref.WeakReference
і java.lang.ref.SoftReference
?
Яка різниця між java.lang.ref.WeakReference
і java.lang.ref.SoftReference
?
Відповіді:
Із розуміння слабких посилань , Етан Ніколас:
Слабкі посилання
Простий посилання , простіше кажучи, - це посилання, яке недостатньо сильне, щоб змусити об'єкт залишитися в пам'яті. Слабкі посилання дозволяють використовувати можливості сміттєзбірника визначати доступність для вас, тому вам не доведеться робити це самостійно. Ви створюєте такий слабкий посилання:
WeakReference weakWidget = new WeakReference(widget);
а потім в іншому місці коду, який ви можете використовувати
weakWidget.get()
для отримання фактичногоWidget
об'єкта. Звичайно, слабка посилання недостатньо сильна, щоб запобігти вивезенню сміття, тому ви можете виявити (якщо немає чітких посилань на віджет), щоweakWidget.get()
раптом починає повертатисяnull
....
М'які посилання
М'яка посилання точно як слабка посилання, за винятком того, що він менш прагне викинути об'єкт , до якого воно відноситься. Об'єкт, який є слабкодоступним (найсильніші посилання на нього
WeakReferences
), буде відкинутий у наступному циклі вивезення сміття, але об'єкт, який буде легко доступний, як правило, на деякий час буде триматися навколо.
SoftReferences
від них не потрібно поводитись інакше, ніжWeakReferences
на практиці, м'якодоступні об'єкти, як правило, зберігаються до тих пір, поки пам’ять не вистачає. Це робить їх відмінною основою для кешу, наприклад кеш зображень, описаний вище, оскільки ви можете дозволити колектору сміття турбуватися як про доступність об'єктів (сильнодоступний об'єкт ніколи не буде видалений з кеша), так і наскільки це погано потрібна пам'ять, яку вони споживають.
А Пітер Кесслер додав у коментарі:
Sun JRE трактує SoftReferences не так, як WeakReferences. Ми намагаємося затримати об’єкт, на який посилається SoftReference, якщо немає тиску на доступну пам'ять. Одна деталь: політика для JRE "-client" та "-server" відрізняється: -client JRE намагається утримати свій слід невеликим, віддаючи перевагу очищенню SoftReferences, а не розширенню купи, тоді як Jser -server намагається зберегти свій продуктивність висока, віддаючи перевагу розширенню купи (якщо можливо), а не очищенню SoftReferences. Один розмір підходить не всім.
Слабкі посилання збираються охоче. Якщо GC виявить, що об'єкт є слабодоступним (він доступний лише через слабкі посилання), він негайно очистить слабкі посилання на цей об’єкт. Таким чином, вони хороші для збереження посилання на об'єкт, на який ваша програма також зберігає (сильно посилається) "пов’язану інформацію", як-от інформація про кешоване відображення про клас або обгортку для об'єкта тощо. Все, що робить немає сенсу триматись після об'єкта, з яким він асоціюється, є GC-ed. Коли слабка посилання очищається, вона вмикається в черзі посилань, що ваш код десь опитується, і він також відкидає пов'язані об'єкти. Тобто ви зберігаєте додаткову інформацію про об’єкт, але ця інформація не потрібна, як тільки об’єкт, на який вона посилається, відходить. Насправді, у певних ситуаціях ви навіть можете підкласифікувати WeakReference та зберігати пов'язану додаткову інформацію про об’єкт у полях підкласу WeakReference. Ще одне типове використання WeakReference - це спільно з Maps для зберігання канонічних екземплярів.
З іншого боку, SoftReferences хороші для кешування зовнішніх рекреаційних ресурсів, оскільки GC зазвичай затримує їх очищення. Хоча гарантується, що всі SoftReferences будуть очищені до того, як OutOfMemoryError буде викинутий, тому вони теоретично не можуть спричинити OOME [*]
Типовим прикладом використання є збереження розібраної форми вмісту з файлу. Ви б застосували систему, де ви завантажуєте файл, розбираєте його та зберігаєте SoftReference до кореневого об'єкта проаналізованого подання. Наступного разу, коли вам потрібен файл, ви спробуєте отримати його через SoftReference. Якщо ви можете отримати його, ви шкодуєте собі ще одне завантаження / розбір, і якщо GC тим часом очистив його, ви перезавантажите його. Таким чином, ви використовуєте вільну пам’ять для оптимізації продуктивності, але не ризикуйте НАДОМОГО.
Тепер для [*]. Збереження SoftReference не може спричинити за собою OOME. Якщо, з іншого боку, ви помилково використовуєте SoftReference для завдання, яке має на увазі використовувати WeakReference (а саме ви зберігаєте інформацію, пов’язану з Об'єктом якось сильно посилається, і відкидаєте її, коли очищається об'єкт Reference), ви можете зіткнутися з OOME як ваш код, який опитує чергу ReferenceQue і відкидає пов'язані об'єкти, може статися таким, що не працює своєчасно.
Отже, рішення залежить від використання - якщо ви кешуєте інформацію, яку дорого будувати, але все-таки реконструювати з інших даних, використовуйте м'які посилання - якщо ви зберігаєте посилання на канонічний примірник деяких даних, або ви хочете мати посилання на об’єкт, не "володіючи ним" (таким чином, не дозволяючи йому бути GC'd), використовувати слабке посилання.
WeakReference
є те, що в місцях, де слід його використовувати, той факт, що він може залишатись дійсним ще деякий час після того, як посилання вийде за межі сфери, може бути допустимим, але небажаним.
WeakReference
яке полягає в спостереженні запусками GC. Див розробки: stackoverflow.com/a/46291143/632951
На Яві ; порядку від найсильнішого до найслабшого, є: Сильний, М'який, Слабкий і Фантомний
Сильна посилання нормальна посилання , яка захищає згаданий об'єкт з колекції з допомогою ОГО. тобто ніколи сміття не збирає.
М'яка посилання має право для збору збирача сміття, але , ймовірно , не збиратиметься , поки його пам'ять не потрібно. тобто сміття збирає раніше OutOfMemoryError
.
Слабка посилання є посиланням , що не захищає об'єкт , на який посилається з колекції з допомогою ГХ. тобто сміття збирається, коли немає сильних або м'яких посилань.
Фантом посилання є посилання на об'єкт phantomly посилається після того, як вона була завершена, але до його виділена пам'ять була утилізована.
Аналогія: Припустимо, що JVM - це королівство, Об'єкт - цар королівства, а GC - це нападник королівства, який намагається вбити царя (об'єкт).
until memory is available
не має сенсу. Ви маєте на увазі is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use
?
Слабка довідка http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Принцип: weak reference
пов'язаний зі збиранням сміття. Зазвичай об’єкти, які мають одну або більше reference
, не можуть брати участь у вивезенні сміття.
Вищезазначений принцип не застосовується, коли він є weak reference
. Якщо об’єкт має лише слабке посилання на інші об'єкти, то його готові до вивезення сміття.
Розглянемо нижченаведений приклад: у нас є Map
об'єкти, де Key посилається на об’єкт.
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> aMap = new
HashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
System.out.println("Size of Map" + aMap.size());
}
}
Тепер, під час виконання програми, яку ми зробили emp = null
. Map
Холдинг ключ не має сенсу тут , як це null
. У наведеній вище ситуації об’єкт не збирається сміттям.
Слабка карта
WeakHashMap
це той, де записи ( key-to-value mappings
) будуть видалені, коли їх більше неможливо отримати з Map
.
Дозвольте мені показати наведений вище приклад те саме з WeakHashMap
import java.util.WeakHashMap;
public class Test {
public static void main(String args[]) {
WeakHashMap<Employee, EmployeeVal> aMap =
new WeakHashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
int count = 0;
while (0 != aMap.size()) {
++count;
System.gc();
}
System.out.println("Took " + count
+ " calls to System.gc() to result in weakHashMap size of : "
+ aMap.size());
}
}
Вихід: Взяв 20 calls to System.gc()
в результаті в aMap size
з: 0.
WeakHashMap
має лише слабкі посилання на ключі, не сильні посилання, як інші Map
класи. Існують ситуації, на які вам слід потурбуватися, коли на значення або ключ сильно посилаються, хоча ви вже використовували WeakHashMap
. Цього можна уникнути, загорнувши об’єкт у слабку референцію .
import java.lang.ref.WeakReference;
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> map =
new HashMap<Employee, EmployeeVal>();
WeakReference<HashMap<Employee, EmployeeVal>> aMap =
new WeakReference<HashMap<Employee, EmployeeVal>>(
map);
map = null;
while (null != aMap.get()) {
aMap.get().put(new Employee("Vinoth"),
new EmployeeVal("Programmer"));
System.out.println("Size of aMap " + aMap.get().size());
System.gc();
}
System.out.println("Its garbage collected");
}
}
М'які посилання.
Soft Reference
трохи сильніше, що слабка посилання. М'яке посилання дозволяє збирати сміття, але благає сміттєзбірника очистити його, лише якщо немає іншого варіанту.
Збирач сміття не агресивно збирає м'якодоступні об'єкти, як це робиться зі слабкодоступними предметами - натомість він збирає лише м'якодоступні об'єкти, якщо йому справді "потрібна" пам'ять. М'які посилання - це спосіб сказати сміттєзбірнику: "Поки пам'ять не надто щільна, я хотів би зберегти цей об'єкт навколо. Але якщо пам'ять стає дуже тісною, продовжуйте збирати її, і я розбираюся З цим." Збирач сміття зобов'язаний очистити всі м'які посилання, перш ніж він може викинути OutOfMemoryError
.
NullPointerException
по прибуттю aMap.get().put(...)
.
WeakHashMap
приклад (оскільки це перший, який демонструє слабку поведінку). Подивіться на doc для "WeakHashMap": "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. "
Вся суть використання WeakHashMap полягає в тому, що вам не потрібно декларувати / вводити WeakReference; WeakHashMap робить це для вас внутрішньо. docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
WeakHashMap
дії, наприклад, додаток, який показує, як видаляються записи лише після виконання сміття, дивіться мій відповідь на запитання, чи слабко зростає WeakHashMap чи чи видаляються ключі від сміття? .
Єдина реальна різниця між м'якою посиланням і слабкою посиланням полягає в тому, що
сміттєзбірник використовує алгоритми, щоб вирішити, повернути чи ні повернути м'якодоступний об'єкт, але завжди відновлює слабкодоступний об'єкт.
SoftReference
призначений для схованок. Коли буде встановлено, що WeakReference
посилається на інакше недоступний об'єкт, він буде видалений негайно. SoftReference
може залишитися як є. Зазвичай існує певний алгоритм, що стосується обсягу вільної пам'яті та часу, який останній використовується, щоб визначити, чи слід його очистити. Поточний алгоритм Sun полягає в тому, щоб очистити посилання, якщо він не використовувався протягом стількох секунд, оскільки на купі Java є мегабайти пам'яті, що не вільна (налаштовується, сервер HotSpot перевіряє максимальну можливу купу, встановлену -Xmx
). SoftReference
s буде очищено, перш ніж OutOfMemoryError
буде кинуто, якщо інше не буде доступно.
java.lang
. Таке зловживання синонімами нікому не приносить користі.
Ця стаття може бути дуже корисною для розуміння сильних, м'яких, слабких та фантомних посилань.
Щоб дати вам підсумок,
Якщо у вас є лише слабкі посилання на об'єкт (без чітких посилань), GC об'єкт буде відтворений в наступному циклі GC.
Якщо у вас є лише м'які посилання на об'єкт (без чітких посилань), GC об'єкт буде відтворений лише тоді, коли у JVM не вистачає пам'яті.
Отже, ви можете сказати, що потужні посилання мають вищу силу (ніколи не може бути зібрана GC)
М'які посилання є потужними, ніж слабкі посилання (оскільки вони можуть уникнути циклу GC, поки у JVM не закінчиться пам'ять)
Слабкі посилання є навіть менш потужними, ніж м'які посилання (оскільки вони не можуть уникнути жодного циклу GC і будуть відтворені, якщо об'єкт не має інших сильних посилань).
Аналогія ресторану
Тепер, якщо ви є надійним клієнтом (аналогічним сильним посиланням), то навіть якщо в ресторан завітає новий клієнт або він так радує, ви ніколи не покинете свій стіл (область пам'яті на купі). Офіціант не має права сказати вам (або навіть просити вас) покинути ресторан.
Якщо ви м'який замовник (аналог м'яких посилань), то, якщо в ресторан приходить новий клієнт, офіціант не попросить вас покинути стіл, якщо не залишиться іншого порожнього столу для розміщення нового клієнта. (Іншими словами, офіціант попросить вас залишити стіл лише у тому випадку, якщо новий клієнт вступив, а для цього нового клієнта не залишилося іншої таблиці)
Якщо ви слабкий клієнт (аналогічний слабкому посиланню), то офіціант за його бажанням може (у будь-який момент часу) попросити вас покинути ресторан: P
Відповідно до документа , вільні WeakReferences повинні бути очищені за допомогою GC.
Відповідно до документа , звільнені SoftReferences повинні бути очищені до викиду OOM.
Це єдина реальна різниця. Все інше не є частиною договору. (Я припускаю, що останні документи є договірними.)
SoftReferences корисні. В кеш-пам'яті кеш-пам'яті використовують SoftReferences, а не WeakReferences.
weak_ref.get()
. Коли null
ви дізнаєтесь, що між цією тривалістю GC пробігав.
Що стосується неправильного використання WeakReference, то список нескінченний:
паршивий хак для впровадження програмного забезпечення prioritet-2, таким чином, що вам не потрібно писати жодного, але він не працює так, як очікувалося, оскільки кеш буде очищений під час кожного запуску GC, навіть якщо є запасна пам'ять. Дивіться https://stackoverflow.com/a/3243242/632951 щодо фалів. (Крім того, що, якщо вам потрібно більше ніж два рівні пріоритету кешу? Вам все одно знадобиться справжня бібліотека.)
невдалий хак для асоціації даних з об'єктом існуючого класу, але він створює витік пам'яті (OutOfMemoryError), коли ваш GC вирішить зробити перерву після створення ваших слабких налаштувань. Окрім того, це не надто потворно: кращим підходом є використання кортежів.
паршивий хак для асоціації даних з об'єктом існуючого класу, де клас має нерв, щоб зробити себе некласифікованим, і використовується у існуючому коді функції, який потрібно викликати. У такому випадку правильним рішенням є або відредагувати клас, і зробити його підкласовим, або відредагувати функцію і змусити її взяти інтерфейс замість класу, або використовувати альтернативну функцію.
equals()
є лише ідентичність об'єкта? М'які посилання там здаються марними, тому що, як тільки ключовий об’єкт вже не може бути доступний, ніхто більше не буде шукати це відображення знову.
Шість типів стану об'єктної доступності на Java:
Детальніше: https://www.artima.com/insidejvm/ed2/gc16.html «крах
Слід пам’ятати, що слабо посилається об’єкт збирається лише тоді, коли він має ТІЛЬКИ слабкі посилання. Якщо у нього стільки одного сильного посилання, він не збирається незалежно від того, скільки слабких посилань у нього є.
Щоб надати аспект використання пам’яті в дії, я провів експеримент із посиланнями Strong, Soft, слабкі та Phantom під великим навантаженням з важкими предметами, зберігаючи їх до кінця програми. Потім проводили моніторинг використання купи та поведінку GC . Ці показники можуть залежати від конкретних випадків, але, безумовно, дають високе розуміння. Нижче наведені результати.
Поводження Heap & GC при сильному навантаженні
Ви можете отримати більш детальні графіки, статистику та спостереження за цим експериментом тут .
Слабка референція : об'єкти, на які посилаються лише слабкі посилання, збираються на кожному циклі GC (незначний або повний).
SoftReference : коли збираються об'єкти, на які є лише м'які посилання, залежить від:
-XX: SoftRefLRUPolicyMSPerMB = N прапор (значення за замовчуванням 1000, aka 1 секунда)
Кількість вільної пам'яті в купі.
Приклад:
Тоді об’єкт, на який посилається лише SoftReference, буде зібраний, якщо останній раз, коли до нього звертався, перевищує 10 секунд.