Java SoftReference Tutorial with Examples
1. SoftReference
No ADS
java.lang.ref.SoftReference class is used to create an object that wraps another object - innerObject. The object it wraps can be removed from memory by Garbage Collector (GC) if it is no longer being used somewhere else stronger than GC and the system is in need of more memory.
The object is wrapped inside a WeakReference that acts like a diner in a restaurant. When diners finish eating, they are ready to leave the table even if at that time the restaurant has many empty tables. SoftReference is a bit different from WeakReference, diners can sit back and only leave if the restaurant has no more free tables or the number of available free tables is less than a safe value.
Basically, it's a bit more difficult to give an example of SoftReference and show you firsthand how Garbage Collector removes soft references from memory, since we need to simulate near-full memory situation. If the simulation is not perfect we will overflow the memory. Although before OutOfMemoryError was thrown, soft references were removed from memory.
Advice: WeakReference should be learned before continuing with SoftReference:
When an object is removed from memory, its finalize() method is called. Note: This method has been marked as deprecated since Java 9, but we can still use it just to print a message.
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");
}
}
The example below shows that GC will remove soft references from memory to avoid throwing an 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 allows you to configure when GC should remove soft references from memory.
-XX:SoftRefLRUPolicyMSPerMB=1000
The default value of SoftRefLRUPolicyMSPerMB parameter is 1000 Milliseconds. This means that if only 10MB of HEAP memory is available, GC will work to remove soft references that have been unused for longer than 1000 milliseconds.
Java documentation says that:
"All soft references to softly-reachable objects are guaranteed to have been freed before the virtual machine throws an OutOfMemoryError."
Apparently the above is only really true when "-XX:SoftRefLRUPolicyMSPerMB=0".
Another better example. Let's try to simulate a situation where Java's memory is near exhaustion:
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)
All methods of SoftReference are inherited from the parent class.
// Methods inherited from parent.
public T get()
public void clear()
public boolean isEnqueued()
public boolean enqueue()
2. SoftReference(T, ReferenceQueue<? super T>
Create a SoftReference object that wraps innerObject object. When innerObject is removed from memory by GC, this SoftReference object will be added to the queue.
SoftReference(T innerObject, ReferenceQueue<? super T> queue)
3. Caching example
No ADS
Sometimes SoftReference is also used in a simple cache system, where the data rarely changes. Java virtual machine automatically removes these data when it needs more memory.
Example: A cache system stores data of image files.
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!
No ADS
Java Basic
- Data Types in java
- Java PhantomReference Tutorial with Examples
- JDK Javadoc in CHM format
- Java Stream Tutorial with Examples
- Java Predicate Tutorial with Examples
- Java BiConsumer Tutorial with Examples
- Arrays in Java
- JDBC Driver Libraries for different types of database in Java
- Abstract class and Interface in Java
- Java Commons Email Tutorial with Examples
- Install Eclipse
- Bitwise Operations
- Install Eclipse on Ubuntu
- Configuring Eclipse to use the JDK instead of JRE
- Java Commons Logging Tutorial with Examples
- Java Enums Tutorial with Examples
- Loops in Java
- Java Regular Expressions Tutorial with Examples
- Install Java on Ubuntu
- Quick Learning Java for beginners
- Install Java on Windows
- Comparing and Sorting in Java
- Inheritance and polymorphism in Java
- Java Consumer Tutorial with Examples
- Java String, StringBuffer and StringBuilder Tutorial with Examples
- Java Exception Handling Tutorial with Examples
- Example of Java encoding and decoding using Apache Base64
- if else statement in java
- Switch Statement in Java
- Java Supplier Tutorial with Examples
- Java Programming for team using Eclipse and SVN
- Java JDBC Tutorial with Examples
- Java remote method invocation - Java RMI Tutorial with Examples
- Java Multithreading Programming Tutorial with Examples
- Customize java compiler processing your Annotation (Annotation Processing Tool)
- What is needed to get started with Java?
- Java Aspect Oriented Programming with AspectJ (AOP)
- Understanding Java System.identityHashCode, Object.hashCode and Object.equals
- Java Compression and Decompression Tutorial with Examples
- Java Reflection Tutorial with Examples
- Install OpenJDK on Ubuntu
- Java String.format() and printf() methods
- History of Java and the difference between Oracle JDK and OpenJDK
- Introduction to the Raspberry Pi
- Java Socket Programming Tutorial with Examples
- Java Generics Tutorial with Examples
- Manipulating files and directories in Java
- Java WeakReference Tutorial with Examples
- Java Commons IO Tutorial with Examples
- History of bits and bytes in computer science
- Which Platform Should You Choose for Developing Java Desktop Applications?
- Java SoftReference Tutorial with Examples
- Syntax and new features in Java 8
- Java Annotations Tutorial with Examples
- Java Function Tutorial with Examples
- Access modifiers in Java
- Java BiFunction Tutorial with Examples
- Get the values of the columns automatically increment when Insert a record using JDBC
- Java Functional Interface Tutorial with Examples
- Java BiPredicate Tutorial with Examples
Show More
- Java Servlet/Jsp Tutorials
- Java Collections Framework Tutorials
- Java API for HTML & XML
- Java IO Tutorials
- Java Date Time Tutorials
- Spring Boot Tutorials
- Maven Tutorials
- Gradle Tutorials
- Java Web Services Tutorials
- Java SWT Tutorials
- JavaFX Tutorials
- Java Oracle ADF Tutorials
- Struts2 Framework Tutorials
- Spring Cloud Tutorials