Die Anleitung zu Java SoftReference
1. SoftReference
Die Klasse java.lang.ref.SoftReference wird verwendet, um ein Objekt zu erstellen, das ein anderes Objekt umschließt - innerObject. Das umschlossene Objekt kann vom Garbage Collector (GC) aus dem Speicher entfernt werden, wenn es nicht mehr an einem anderen Ort verwendet wird, der stärker als GC ist und das System mehr Speicher benötigt.
Das Objekt ist in eine WeakReference eingebettet, die sich wie ein Diner in einem Restaurant verhält. Wenn die Gäste mit dem Essen fertig sind, sind sie bereit, den Tisch zu verlassen, auch wenn das Restaurant zu dieser Zeit viele leere Tische hat. SoftReference unterscheidet sich ein wenig von WeakReference, Gäste können sich zurücklehnen und nur gehen, wenn das Restaurant keine freien Tische mehr hat oder die Anzahl der verfügbaren freien Tische unter einem sicheren Wert liegt.
Grundsätzlich ist es etwas schwieriger, ein Beispiel für SoftReference zu geben und Ihnen aus erster Hand zu zeigen, wie Garbage Collector weiche Referenzen aus dem Speicher entfernt, da wir eine Situation mit nahezu vollem Speicher simulieren müssen. Wenn die Simulation nicht perfekt ist, wird der Speicher überlaufen. Obwohl vor dem Auslösen von OutOfMemoryError weiche Verweise aus dem Speicher entfernt wurden.
Hinweis: WeakReference sollte erlernt werden, bevor Sie mit SoftReference fortfahren:
Wenn ein Objekt aus dem Speicher entfernt wird, wird seine Methode finalize() aufgerufen. Hinweis: Diese Methode wurde seit Java 9 als veraltet markiert, wir können sie jedoch weiterhin nur zum Drucken einer Nachricht verwenden.
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");
}
}
Das folgende Beispiel zeigt, dass GC weiche Verweise aus dem Speicher entfernt, um das Auslösen eines OutOfMemoryErrorr zu vermeiden.
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 ermöglicht Ihnen zu konfigurieren, wann GC Soft-Referenzen aus dem Speicher entfernen soll.
-XX:SoftRefLRUPolicyMSPerMB=1000
Der Standardwert des Parameters SoftRefLRUPolicyMSPerMB beträgt 1000 Millisekunden. Dies bedeutet, dass wenn nur der Speicher HEAP nur 10MB verfügbar sind, GC wird Soft-Referenzen entfernt, die länger als 1000 Millisekunden nicht verwendet wurden.
Die Dokumentation Java sagt, dass:
"All soft references to softly-reachable objects are guaranteed to have been freed before the virtual machine throws an OutOfMemoryError." - Alle Soft-Referenzen auf weich erreichbare Objekte werden garantiert freigegeben, bevor die virtuelle Maschine einen OutOfMemoryError auslöst.
Anscheinend ist das obige nur dann wirklich wahr, wenn "-XX:SoftRefLRUPolicyMSPerMB=0".
Noch ein besseres Beispiel. Versuchen wir, eine Situation zu simulieren, in der den Speicher von Java fast erschöpft ist:
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)
Alle Methoden von SoftReference werden von der Elternklasse geerbt.
// Methods inherited from parent.
public T get()
public void clear()
public boolean isEnqueued()
public boolean enqueue()
2. SoftReference(T, ReferenceQueue<? super T>
Erstellen Sie ein Objekt SoftReference, das das Objekt innerObject umschließt. Wenn innerObject von GC aus dem Speicher entfernt wird, wird dieses Objekt SoftReference der queue hinzugefügt.
SoftReference(T innerObject, ReferenceQueue<? super T> queue)
3. Caching example
Manchmal wird SoftReference auch in einem einfachen System cache verwendet, in dem sich die Daten selten ändern. Die Virtual Machine Java entfernt diese Daten automatisch, wenn sie mehr Arbeitsspeicher benötigt.
Beispiel: Ein System cache speichert Daten von Bilddateien
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 Grundlagen
- Anpassen von Java-Compiler, der Ihre Annotation verarbeitet (Annotation Processing Tool)
- Java Programmierung für Team mit Eclipse und SVN
- Die Anleitung zu Java WeakReference
- Die Anleitung zu Java PhantomReference
- Komprimierung und Dekomprimierung in Java
- Konfigurieren von Eclipse zur Verwendung des JDK anstelle von JRE
- Java-Methoden String.format() und printf()
- Syntax und neue Funktionen in Java 8
- Die Anleitung zu Java Reguläre Ausdrücke
- Die Anleitung zu Java Multithreading Programming
- JDBC Driver Bibliotheken für verschiedene Arten von Datenbank in Java
- Die Anleitung zu Java JDBC
- Holen Sie sich die automatisch erhöhenden Wert der Spalte bei dem Insert eines Rekord, der JDBC benutzt
- Die Anleitung zu Java Stream
- Die Anleitung zu Java Functional Interface
- Einführung in Raspberry Pi
- Die Anleitung zu Java Predicate
- Abstrakte Klasse und Interface in Java
- Zugriffsmodifikatoren (Access modifiers) in Java
- Die Anleitung zu Java Enum
- Die Anleitung zu Java Annotation
- Vergleichen und Sortieren in Java
- Die Anleitung zu Java String, StringBuffer und StringBuilder
- Die Anleitung zu Java Exception
- Die Anleitung zu Java Generics
- Manipulieren von Dateien und Verzeichnissen in Java
- Die Anleitung zu Java BiPredicate
- Die Anleitung zu Java Consumer
- Die Anleitung zu Java BiConsumer
- Was ist erforderlich, um mit Java zu beginnen?
- Geschichte von Java und der Unterschied zwischen Oracle JDK und OpenJDK
- Installieren Sie Java unter Windows
- Installieren Sie Java unter Ubuntu
- Installieren Sie OpenJDK unter Ubuntu
- Installieren Sie Eclipse
- Installieren Sie Eclipse unter Ubuntu
- Schnelle lernen Java für Anfänger
- Geschichte von Bits und Bytes in der Informatik
- Datentypen in Java
- Bitweise Operationen
- if else Anweisung in Java
- Switch Anweisung in Java
- Schleifen in Java
- Die Anleitung zu Java Array
- JDK Javadoc im CHM-Format
- Vererbung und Polymorphismus in Java
- Die Anleitung zu Java Function
- Die Anleitung zu Java BiFunction
- Beispiel für Java Encoding und Decoding mit Apache Base64
- Die Anleitung zu Java Reflection
- Java-Remote-Methodenaufruf - Java RMI
- Die Anleitung zu Java Socket
- Welche Plattform sollten Sie wählen für Applikationen Java Desktop entwickeln?
- Die Anleitung zu Java Commons IO
- Die Anleitung zu Java Commons Email
- Die Anleitung zu Java Commons Logging
- Java System.identityHashCode, Object.hashCode und Object.equals verstehen
- Die Anleitung zu Java SoftReference
- Die Anleitung zu Java Supplier
- Java Aspect Oriented Programming mit AspectJ (AOP)
Show More
- Anleitungen Java Servlet/JSP
- Die Anleitungen Java Collections Framework
- Java API für HTML & XML
- Die Anleitungen Java IO
- Die Anleitungen Java Date Time
- Anleitungen Spring Boot
- Anleitungen Maven
- Anleitungen Gradle
- Anleitungen Java Web Services
- Anleitungen Java SWT
- Die Anleitungen JavaFX
- Die Anleitungen Oracle Java ADF
- Die Anleitungen Struts2 Framework
- Anleitungen Spring Cloud