Le Tutoriel de Java SoftReference
1. SoftReference
La classe java.lang.ref.SoftReference est utilisée pour créer un objet qui enveloppe (wrap) un autre objet - innerObject. L'objet qu'il encapsule peut être supprimé de la mémoire par Garbage Collector (GC) s'il n'est plus utilisé ailleurs que par GC et que le système a besoin de plus de mémoire.
L'objet est enveloppé dans une WeakReference qui agit comme un diner dans un restaurant. Lorsque les convives ont fini de manger, ils sont prêts à quitter la table même si à ce moment-là, le restaurant a de nombreuses tables vides. SoftReference est un peu différent de WeakReference, les convives peuvent s'asseoir et ne partir que si le restaurant n'a plus de tables libres ou si le nombre de tables libres disponibles est inférieur à une valeur sûre.
En règle générale, il est plus difficile de donner un exemple de SoftReference et de vous montrer comment Garbage Collector supprime les références logicielles de la mémoire, car on doit simuler une situation de mémoire presque pleine. Si la simulation n'est pas parfaite, la mémoire sera débordée. Bien qu'avant la levée d'OutOfMemoryError, les références logicielles étaient supprimées de la mémoire.
Conseil: WeakReference doit être appris avant de continuer avec SoftReference:
Lorsqu'un objet est supprimé de la mémoire, sa méthode finalize() est convoquée. Remarque: cette méthode a été marquée comme obsolète depuis Java 9, mais on peut toujours l'utiliser uniquement pour imprimer un 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");
}
}
L'exemple ci-dessous montre que GC supprimera les références logicielles de la mémoire pour éviter de générer une 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 vous permet de configurer quand GC doit supprimer les références logicielles de la mémoire.
-XX:SoftRefLRUPolicyMSPerMB=1000
La valeur par défaut du paramètre SoftRefLRUPolicyMSPerMB est de 1000 millisecondes. Cela signifie que si seulement 10MB de mémoire HEAP sont disponibles, GC s'efforcera de supprimer les références logicielles qui ont été inutilisées pendant plus de 1000 millisecondes.
Selon les documents sur Java:
«Toutes les références logicielles à des objets facilement accessibles sont garanties d'avoir été libérées avant que la machine virtuelle ne renvoie une erreur OutOfMemoryError.»
Il paraît que cette remarque est seulement juste lorsque "-XX:SoftRefLRUPolicyMSPerMB=0".
Un autre meilleur exemple. Essayer de simuler une situation dans laquelle la mémoire de Java est presque épuisée:
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)
Toutes les méthodes de SoftReference sont héritées de la classe parentale.
// Methods inherited from parent.
public T get()
public void clear()
public boolean isEnqueued()
public boolean enqueue()
2. SoftReference(T, ReferenceQueue<? super T>
Créer un objet SoftReference qui enveloppe l'objet innerObject. Lorsque innerObject est supprimé de la mémoire par GC, cet objet SoftReference sera ajouté à queue.
SoftReference(T innerObject, ReferenceQueue<? super T> queue)
3. Caching example
Parfois, SoftReference est également utilisé dans un système de cache simple, où les données changent rarement. La machine virtuelle Java supprime automatiquement ces données lorsqu'elle a besoin de plus de mémoire.
Exemple: Un système de cache stocke les données des fichiers image.
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
- Personnaliser le compilateur Java pour traiter votre annotation (Annotation Processing Tool)
- Programmation Java pour l'équipe utilisant Eclipse et SVN
- Le Tutoriel de Java WeakReference
- Le Tutoriel de Java PhantomReference
- Tutoriel sur la compression et la décompression Java
- Configuration d'Eclipse pour utiliser le JDK au lieu de JRE
- Méthodes Java String.format() et printf()
- Syntaxe et nouvelles fonctionnalités de Java 8
- Expression régulière en Java
- Tutoriel de programmation Java multithreading
- Bibliothèques de pilotes JDBC pour différents types de bases de données en Java
- Tutoriel Java JDBC
- Obtenir des valeurs de colonne automatiquement incrémentées lors de l'insertion d'un enregistrement à l'aide de JDBC
- Le Tutoriel de Java Stream
- Le Tutoriel de Java Functional Interface
- Introduction à Raspberry Pi
- Le Tutoriel de Java Predicate
- Classe abstraite et interface en Java
- Modificateurs d'accès en Java
- Le Tutoriel de Java Enum
- Le Tutoriel de Java Annotation
- Comparer et trier en Java
- Le Tutoriel de Java String, StringBuffer et StringBuilder
- Tutoriel de gestion des exceptions Java
- Le Tutoriel de Java Generics
- Manipulation de fichiers et de répertoires en Java
- Le Tutoriel de Java BiPredicate
- Le Tutoriel de Java Consumer
- Le Tutoriel de Java BiConsumer
- Qu'est-ce qui est nécessaire pour commencer avec Java?
- L'histoire de Java et la différence entre Oracle JDK et OpenJDK
- Installer Java sur Windows
- Installer Java sur Ubuntu
- Installer OpenJDK sur Ubuntu
- Installer Eclipse
- Installer Eclipse sur Ubuntu
- Le Tutoriel Java pour débutant
- Histoire des bits et des bytes en informatique
- Types de données dans Java
- Opérations sur les bits
- Le Tutoriel de instruction Java If else
- Le Tutoriel de instruction Java Switch
- Les Boucles en Java
- Les Tableaux (Array) en Java
- JDK Javadoc au format CHM
- Héritage et polymorphisme en Java
- Le Tutoriel de Java Function
- Le Tutoriel de Java BiFunction
- Exemple de Java encoding et decoding utilisant Apache Base64
- Le Tutoriel de Java Reflection
- Invocation de méthode à distance en Java
- Le Tutoriel de Java Socket
- Quelle plate-forme devez-vous choisir pour développer des applications de bureau Java?
- Le Tutoriel de Java Commons IO
- Le Tutoriel de Java Commons Email
- Le Tutoriel de Java Commons Logging
- Comprendre Java System.identityHashCode, Object.hashCode et Object.equals
- Le Tutoriel de Java SoftReference
- Le Tutoriel de Java Supplier
- Programmation orientée aspect Java avec AspectJ (AOP)
Show More
- Tutoriels de programmation Java Servlet/JSP
- Tutoriels de Java Collections Framework
- Tutoriels Java API pour HTML & XML
- Tutoriels Java IO
- Tutoriels Java Date Time
- Tutoriels Spring Boot
- Tutoriels Maven
- Tutoriels Gradle
- Tutoriels Java Web Service
- Tutoriels de programmation Java SWT
- Tutoriels de JavaFX
- Tutoriels Java Oracle ADF
- Tutoriels Struts2
- Tutoriels Spring Cloud