Руководство Java SoftReference
1. SoftReference
Класс java.lang.ref.SoftReference используется для создания объекта, который обертывает (wrap) другой объект - innerObject. Объект, который он обертывает, может быть удален из памяти by Garbage Collector (GC) (сборщиком мусора), если он больше не используется в другом месте, более сильном, чем GC, и системе требуется больше памяти.

Объект завернут в WeakReference, действует как посетитель в ресторане. Когда посетители заканчивают есть, они готовы покинуть стол, даже если в это время в ресторане много пустых столов. SoftReference немного отличается от WeakReference, посетители могут оставаться и уходить только в том случае, если в ресторане больше нет свободных столов или количество свободных столов меньше безопасного значения.

В принципе, немного сложнее привести пример о SoftReference и показать вам, как Garbage Collector удаляет мягкие ссылки из памяти, поскольку нам нужно смоделировать ситуацию с почти полной памятью. Если симуляция не идеальна, мы переполняем память. Хотя до того, как был выброшен OutOfMemoryError, мягкие ссылки были удалены из памяти.
Совет: WeakReference должна быть изучена, прежде чем продолжать использовать SoftReference:
Когда объект удаляется из памяти, вызывается его finalize(). Примечание: Этот метод был помечен как устаревший (deprecated) с Java 9, но мы все еще можем использовать его только для печати сообщения.
AnyObject.java
package org.o7planning.beans;
public class AnyObject {
private String val;
public AnyObject(String val) {
this.val = val;
}
public String getVal() {
return this.val;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("I am being removed from memory");
}
}В приведенном ниже примере показано, что GC удалит мягкие ссылки из памяти, чтобы избежать ошибки OutOfMemoryError.
SoftReference_obj_ex1.java
package org.o7planning.softreference.ex;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
import org.o7planning.beans.AnyObject;
public class SoftReference_obj_ex1 {
public static void main(String[] args) throws InterruptedException {
// Create myAnyObject reference points to AnyObject("Obj1").
AnyObject myAnyObject = new AnyObject("Obj1");
// Create SoftReference object
SoftReference<AnyObject> softRef = new SoftReference<AnyObject>(myAnyObject);
System.out.println("softRef.get(): " + softRef.get());
List<String> list= new ArrayList<String>();
int i = 0;
String s = "";
while (true) {
AnyObject innerObject = softRef.get();
if (innerObject == null) {
System.out.println("Inner object is removed by Garbage Collector");
System.out.println("softRef.get(): " + innerObject);
break;
}
i++;
//
s = s + " String " + i; // Throw OutOfMemoryError
list.add(s);
System.out.println("Create new String: " + i);
}
}
}Output:
softRef.get(): org.o7planning.beans.AnyObject@5e91993f
Create new String: 1
Create new String: 2
...
Create new String: 24952
Create new String: 24953
Create new String: 24954
Exception in thread "main" I am being removed from memory
java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.Arrays.copyOfRange(Arrays.java:4030)
at java.base/java.lang.StringLatin1.newString(StringLatin1.java:715)
at java.base/java.lang.StringBuilder.toString(StringBuilder.java:448)
at org.o7planning.softreference.ex.SoftReference_obj_ex1.main(SoftReference_obj_ex1.java:33)Java позволяет настроить, когда GC должен удалять мягкие ссылки из памяти.
-XX:SoftRefLRUPolicyMSPerMB=1000Значение параметра SoftRefLRUPolicyMSPerMB по умолчанию составляет 1000 миллисекунд. Это означает, что если доступно только 10MB памяти HEAP, GC будет работать для удаления мягких ссылок, которые не использовались более 1000 миллисекунд.
В документации о Java говорится, что:
"Все мягкие ссылки на мягко достижимые объекты гарантированно будут освобождены до того, как виртуальная машина выдаст ошибку OutOfMemoryError."
По-видимому, вышесказанное действительно верно только тогда, когда "-XX:SoftRefLRUPolicyMSPerMB=0".
Еще один лучший пример. Давайте попробуем смоделировать ситуацию, когда память Java близка к исчерпанию:
SoftReference_obj_ex2.java
package org.o7planning.softreference.ex;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
import org.o7planning.beans.AnyObject;
public class SoftReference_obj_ex2 {
public static void main(String[] args) throws InterruptedException {
// A String has size of 1Mb.
String oneMbString = create1MbString();
// Create myAnyObject (~2 Mb in HEAP).
AnyObject myAnyObject = new AnyObject(oneMbString + oneMbString);
// Create SoftReference object
SoftReference<AnyObject> softRef = new SoftReference<AnyObject>(myAnyObject);
System.out.println("softRef.get(): " + softRef.get());
myAnyObject = null;
List<String> list = new ArrayList<String>();
int i = 0;
while (true) {
i++;
long freeMemoryInBytes = Runtime.getRuntime().freeMemory(); // in bytes
long freeMemoryInMbs = freeMemoryInBytes / (1024 * 1024);
System.out.println("Free memory in Mb: " + freeMemoryInMbs);
//
if (freeMemoryInMbs <= 10) {
Thread.sleep(1200);
}
if (freeMemoryInMbs <= 2) {
System.out.println("Done!");
break;
}
System.out.println(" >> Create new String");
String s = oneMbString + " - " + i;
list.add(s);
}
}
// Create a String has the size of 1MB.
// 1MB = 1024KB = 1024x1024 bytes = (2^10)*(2^10) bytes = 2^20 bytes.
private static String create1MbString() {
String s = "A"; // 2 bytes
for (int i = 0; i < 20; i++) {
s = s + s;
}
return s;
}
}Output:
softRef.get(): org.o7planning.beans.AnyObject@5e91993f
Free memory in Mb: 238
>> Create new String
...
Free memory in Mb: 16
>> Create new String
Free memory in Mb: 12
>> Create new String
Free memory in Mb: 8
>> Create new String
Free memory in Mb: 14
>> Create new String
Free memory in Mb: 10
>> Create new String
Free memory in Mb: 10
>> Create new String
Free memory in Mb: 8
>> Create new String
Free memory in Mb: 6
>> Create new String
Free memory in Mb: 4
I am being removed from memory
>> Create new String
Free memory in Mb: 2
Done!SoftReference constructors
SoftReference(T referent)
SoftReference(T referent, ReferenceQueue<? super T> queue)Все методы of SoftReference наследуются от родительского класса.
// Methods inherited from parent.
public T get()
public void clear()
public boolean isEnqueued()
public boolean enqueue()2. SoftReference(T, ReferenceQueue<? super T>
Создайте объект SoftReference, который обертывает объект innerObject. Когда innerObject удаляется из памяти by GC, этот объект SoftReference будет добавлен в queue.
SoftReference(T innerObject, ReferenceQueue<? super T> queue)3. Caching example
Иногда SoftReference также используется в простой системе cache, где данные редко меняются. Виртуальная машина Java автоматически удаляет эти данные, когда ей требуется больше памяти.
Например: Система cache хранит данные файлов изображений.
ImageCache.java
package org.o7planning.softreference.cache.ex;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
public class ImageCache {
private static final ImageCache instance = new ImageCache();
private Map<String, SoftReference<byte[]>> cacheMap = new HashMap<>();
private ImageCache() {
}
public static ImageCache getInstance() {
return instance;
}
public byte[] getImageData(String imagePath) {
SoftReference<byte[]> value = this.cacheMap.get(imagePath);
byte[] data = null;
if(value == null || (data = value.get()) == null) {
data = this.readImageFromDisk(imagePath);
this.cacheMap.put(imagePath, new SoftReference<byte[]>(data));
System.out.println(">> Load data from disk: " + imagePath);
} else {
System.out.println(" Found data in cache: " + imagePath);
}
return data;
}
private byte[] readImageFromDisk(String imagePath) {
// Read from disk..
return new byte[3];
}
}ImageCacheTest.java
package org.o7planning.softreference.cache.ex;
public class ImageCacheTest {
public static void main(String[] args) throws InterruptedException {
String[] imagePaths = new String[] { //
"image1.png", //
"image1.png", //
"image2.png", //
"image2.png", //
"image1.png", //
"image3.png", //
"image3.png", //
"image1.png", //
};
ImageCache cache = ImageCache.getInstance();
for (int i = 0; i < imagePaths.length; i++) {
byte[] data = cache.getImageData(imagePaths[i]);
Thread.sleep(500);
}
System.out.println("Done!");
}
}Output:
>> Load data from disk: image1.png
Found data in cache: image1.png
>> Load data from disk: image2.png
Found data in cache: image2.png
Found data in cache: image1.png
>> Load data from disk: image3.png
Found data in cache: image3.png
Found data in cache: image1.png
Done!Java Basic
- Настройте java compiler для обработки вашего Annotation (Annotation Processing Tool)
- Программирование на Java для группы с помощью Eclipse и SVN
- Руководство Java WeakReference
- Руководство Java PhantomReference
- Сжатие и декомпрессия в Java
- Настройка Eclipse для использования JDK вместо JRE
- Методы String.format() и printf() в Java
- Синтаксис и новые функции в Java 8
- Регулярные выражения Java
- Руководство Java Multithreading Programming
- Библиотеки Java JDBC Driver для различных типов баз данных
- Руководство Java JDBC
- Получить значения столбцов, автоматически возрастающих при вставлении (Insert) записи, используя JDBC
- Руководство Java Stream
- Руководство Java Functional Interface
- Введение в Raspberry Pi
- Руководство Java Predicate
- Абстрактный класс и Interface в Java
- Модификатор доступа (Access modifiers) в Java
- Руководство Java Enum
- Руководство Java Annotation
- Сравнение и Сортировка в Java
- Руководство Java String, StringBuffer и StringBuilder
- Обработка исключений Java - Java Exception Handling
- Руководство Java Generics
- Манипулирование файлами и каталогами в Java
- Руководство Java BiPredicate
- Руководство Java Consumer
- Руководство Java BiConsumer
- Что мне нужно для начала работы с Java?
- История Java и разница между Oracle JDK и OpenJDK
- Установить Java в Windows
- Установите Java в Ubuntu
- Установите OpenJDK в Ubuntu
- Установить Eclipse
- Установите Eclipse в Ubuntu
- Быстрое изучение Java для начинающих
- История бит и байтов в информатике
- Типы данных в java
- Битовые операции
- Команда if else в Java
- команды switch в Java
- Циклы в Java
- Массивы (Array) в Java
- JDK Javadoc в формате CHM
- Наследование и полиморфизм в Java
- Руководство Java Function
- Руководство Java BiFunction
- Пример Java encoding и decoding с использованием Apache Base64
- Руководство Java Reflection
- Java Удаленный вызов методов - Java RMI
- Руководство Программирование Java Socket
- Какую платформу я должен выбрать для разработки приложений Java Desktop?
- Руководство Java Commons IO
- Руководство Java Commons Email
- Руководство Java Commons Logging
- Понимание Java System.identityHashCode, Object.hashCode и Object.equals
- Руководство Java SoftReference
- Руководство Java Supplier
- Аспектно-ориентированное программирование Java с помощью AspectJ (AOP)
Show More
- Руководства Java Servlet/JSP
- Руководства Java Collections Framework
- Java API для HTML, XML
- Руководства Java IO
- Руководства Java Date Time
- Руководства Spring Boot
- Руководства Maven
- Руководства Gradle
- Руководства Java Web Services
- Руководства Java SWT
- Руководства JavaFX
- Руководства Oracle Java ADF
- Руководства Struts2 Framework
- Руководства Spring Cloud