Руководство 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