Evitar eficazmente OOM (OutOfMemory)
En Java, JVM es responsable de la asignación y recuperación de memoria. Esta es su ventaja (fácil de usar, el programa ya no tiene que preocuparse por la memoria como el uso de c), pero también es su desventaja (no lo suficientemente flexible). Para resolver el problema de las operaciones de memoria inflexibles, se pueden utilizar métodos como referencias suaves.
- Referencias fuertes (comunes):Tanto el objeto como el str son referencias fuertes
Object object = new Object();
String str = "hello";
Siempre y cuando un objeto tenga una referencia sólida asociada a él, la JVM definitivamente no reclamará este objeto. Incluso en el caso de memoria insuficiente, la JVM prefiere lanzar un error OutOfMemory que reclamar este objeto.
p. ej.:
public class Main {
public static void main(String[] args) {
new Main().fun1();
}
public void fun1() {
Object object = new Object();
Object[] objArr = new Object[1000];
}
}
Explicación: <1>. Cuando se ejecuta a Object[] objArr = nuevo objeto[1000]; esta frase, si la memoria es insuficiente, la JVM producirá un error OOM y no reclamará el objeto señalado por el objeto.
<2>. Pero hay que tener en cuenta que cuando fun1 está terminado, el objeto y el objArr ya no existen, por lo que los objetos que apuntan a serán reciclados por la JVM.
Suplemento: Si desea romper la relación entre una referencia segura y un objeto, puede asignar explícitamente la referencia a null, de modo que la JVM reclame el objeto en un momento adecuado.
Por ejemplo, el método clear de la clase Vector implementa el trabajo de limpieza asignando el valor de referencia a null.
2. Referencia suave:
Definición: Se utiliza para describir algunos objetos útiles pero no necesarios, representados por la clase java.lang.ref.SoftReference en Java.
Uso: Para un objeto asociado a una referencia suave, la JVM solo reclamará el objeto cuando la memoria sea insuficiente. Por lo tanto, este punto se puede utilizar para resolver el problema OOM, y esta característica es muy adecuada para implementar el almacenamiento en caché: como el almacenamiento en caché de páginas web, el almacenamiento en caché de imágenes, etc.
Código específico: Se puede utilizar una referencia suave junto con una cola de referencia (ReferenceQueue). Si la JVM recicla el objeto al que hace referencia la referencia suave, la referencia suave se agregará a la cola de referencia asociada a él. Este es un ejemplo de uso:
import java.lang.ref.SoftReference;
public class Main {
public static void main(String[] args) {
SoftReference<String> sr = new SoftReference<String>(new String("hello"));
System.out.println(sr.get());
}
}
3. Referencias débiles:
Definición: las referencias débiles también se utilizan para describir objetos no esenciales. Cuando la JVM realiza la recolección de elementos no utilizados, independientemente de si la memoria es suficiente, se reciclarán los objetos asociados a las referencias débiles (Diferencia de referencias suaves). En Java, está representado por la clase java.lang.ref.WeakReference. A continuación se muestra un ejemplo de uso:
import java.lang.ref.WeakReference;
public class Main {
public static void main(String[] args) {
WeakReference<String> sr = new WeakReference<String>(new String("hello"));
System.out.println(sr.get());
System.gc(); //Notify the gc of the JVM to perform garbage collection
System.out.println(sr.get());
}
}
The output result is:
hello
null
Nota: El segundo resultado de salida es null, lo que significa que mientras la JVM realice la recolección de elementos no utilizados, los objetos asociados con referencias débiles definitivamente se reciclarán. Sin embargo, debe tenerse en cuenta que el objeto asociado a una referencia débil mencionada aquí significa que sólo una referencia débil está asociada a él. Si hay una referencia fuerte asociada a él al mismo tiempo, el objeto no se recuperará durante la recolección de elementos no utilizados (lo mismo es cierto para las referencias suaves).
4. Referencia virtual:
Definición: La referencia virtual es diferente de la referencia suave anterior y la referencia débil, no afecta al ciclo de vida del objeto. En Java, está representado por la clase java.lang.ref.PhantomReference.
Uso: Si un objeto está asociado a una referencia fantasma, es lo mismo que ninguna referencia asociada a él y puede ser recogido por el recolector de elementos no utilizados en cualquier momento.
Debe tenerse en cuenta que la referencia virtual debe utilizarse en asociación con la cola de referencia. Cuando el recolector de elementos no utilizados está a punto de reciclar un objeto, si encuentra que tiene una referencia virtual, agregará la referencia virtual a la cola de referencia asociada a él. El programa puede determinar si el objeto al que se hace referencia se recopilará sin elementos no utilizados a juzgar si se ha agregado una referencia virtual a la cola de referencia. Si el programa encuentra que se ha agregado una referencia fantasma a la cola de referencia, puede realizar las acciones necesarias antes de recuperar la memoria del objeto al que se hace referencia.
Referencias suaves y referencias débiles
Similitudes: Se utilizan para describir objetos no esenciales
la diferencia: Los objetos asociados con referencias suaves solo se reciclarán cuando la memoria sea insuficiente, y los objetos asociados con referencias débiles siempre se reciclarán cuando la JVM realice la junta de basuración
En la clase SoftReference, hay tres métodos, dos métodos de construcción y un método get (WekReference es similar):
public SoftReference(T referent) {
super(referent);
this.timestamp = clock;
}
public SoftReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
this.timestamp = clock;
}
El método get se utiliza para obtener la referencia del objeto asociado a la referencia suave. Si el objeto se recicla, devuelve null.
Cuando usamos referencias suaves y referencias débiles, podemos pasar explícitamenteSystem.gc()Para notificar a la JVM para la recolección de basura, pero cabe señalar que aunque se emite la notificación, la JVM no puede ejecutarse inmediatamente, es decir, esta sentencia esNo hay garantía de que la JVM sea recolectada basura en este momento。
Escenarios de aplicación:
Supongamos que nuestra aplicación utilizará una gran cantidad de imágenes predeterminadas, como el avatar predeterminado, iconos de juego predeterminados, etc., estas imágenes se utilizarán en muchos lugares. Si lee la imagen cada vez, porque la lectura del archivo requiere operaciones de hardware, la velocidad es lenta y el rendimiento es menor. Así que consideramos almacenar en caché la imagen y leerla directamente desde la memoria cuando sea necesario. Sin embargo, debido a que las imágenes ocupan una gran cantidad de espacio de memoria, almacenar en caché una gran cantidad de imágenes requiere mucha memoria, y las excepciones OutOfMemory pueden ocurrir más fácilmente. En este momento, podemos considerar el uso de tecnología de referencia suave para evitar este problema.
Primero defina un HashMap para guardar el objeto de referencia suave.
private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
Vamos a definir un método para guardar la referencia suave de Bitmap a HashMap.
public void addBitmapToCache(String path) {
// Strongly referenced Bitmap object
Bitmap bitmap = BitmapFactory.decodeFile(path);
// Bitmap object of soft reference
SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
// Add the object to the Map to make it cache
imageCache.put(path, softBitmap);
}
Al obtener, el objeto Bitmap se puede obtener a través del método get() de SoftReference.
public Bitmap getBitmapByPath(String path) {
// Get the soft-referenced Bitmap object from the cache
SoftReference<Bitmap> softBitmap = imageCache.get(path);
// Determine whether there is a soft reference
if (softBitmap == null) {
return null;
}
// Take out the Bitmap object, if the Bitmap is recycled due to insufficient memory, it will be empty
Bitmap bitmap = softBitmap.get();
return bitmap;
}
Nota:Antes de que el recolector de elementos no utilizados reclame este objeto Java, el método get proporcionado por la clase SoftReference devolverá una referencia segura al objeto Java. Una vez que el subproceso de elementos no utilizados reclame el objeto Java, el método get devolverá null. Por lo tanto, en el código para obtener el objeto de referencia suave, es necesario determinar si es null, con el fin de evitar la aparición de NullPointerException y hacer que la aplicación se bloquee.
Suplemento: Similar a la función de referencia débil es WeakHashMap. Para una clave determinada en WeakHashMap, la existencia de su asignación no impide que el recolector de elementos no utilizados reclame la clave. Después del reciclaje, sus entradas se eliminan efectivamente del mapa. WeakHashMap utiliza este mecanismo implementado por ReferenceQueue.
.