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





