Estoy utilizando una biblioteca de búsqueda que aconseja mantener abierto el objeto del manejador de búsqueda para que esto pueda beneficiar el caché de consultas. Durante el tiempo que he observado, la memoria caché tiende a hincharse (unos pocos cientos de megas y sigue creciendo) y los OOM comenzaron a funcionar. No hay forma de imponer límites a esta memoria caché ni planificar cuánta memoria puede usar. Así que he aumentado el límite Xmx, pero eso es solo una solución temporal al problema.Finalizando con agrado el referente de SoftReference
Finalmente, estoy pensando en hacer de este objeto un referente de java.lang.ref.SoftReference
. Entonces, si el sistema tiene poca memoria libre, dejará que el objeto se vaya y se creará uno nuevo bajo demanda. Esto disminuiría un poco la velocidad después del nuevo arranque, pero esta es una alternativa mucho mejor que golpear OOM.
El único problema que veo sobre SoftReferences es que no hay una forma clara de obtener sus referentes finalizados. En mi caso, antes de destruir el identificador de búsqueda, necesito cerrarlo, de lo contrario, el sistema podría quedarse sin descriptores de archivo. Obviamente, puedo envolver este controlador en otro objeto, escribir un finalizador en él (o engancharlo en una ReferenceQueue/PhantomReference) y soltarlo. Pero bueno, cada artículo de este planeta desaconseja el uso de finalizadores, y especialmente - contra los finalizadores para liberar manejadores de archivos (por ejemplo, Java efectivo ed. II, página 27.).
Así que estoy algo perplejo. ¿Debería ignorar cuidadosamente todos estos consejos y continuar? De lo contrario, ¿hay alguna otra alternativa viable? Gracias por adelantado.
EDIT # 1: El texto a continuación se agregó después de probar algún código como lo sugirió Tom Hawtin. Para mí, parece que cualquiera de las sugerencias no funciona o me falta algo. Aquí está el código:
class Bloat { // just a heap filler really
private double a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;
private final int ii;
public Bloat(final int ii) {
this.ii = ii;
}
}
// as recommended by Tom Hawtin
class MyReference<T> extends SoftReference<T> {
private final T hardRef;
MyReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
this.hardRef = referent;
}
}
//...meanwhile, somewhere in the neighbouring galaxy...
{
ReferenceQueue<Bloat> rq = new ReferenceQueue<Bloat>();
Set<SoftReference<Bloat>> set = new HashSet<SoftReference<Bloat>>();
int i=0;
while(i<50000) {
// set.add(new MyReference<Bloat>(new Bloat(i), rq));
set.add(new SoftReference<Bloat>(new Bloat(i), rq));
// MyReference<Bloat> polled = (MyReference<Bloat>) rq.poll();
SoftReference<Bloat> polled = (SoftReference<Bloat>) rq.poll();
if (polled != null) {
Bloat polledBloat = polled.get();
if (polledBloat == null) {
System.out.println("is null :(");
} else {
System.out.println("is not null!");
}
}
i++;
}
}
Si corro el fragmento anterior con -Xmx10m
y SoftReferences (como en el código anterior), estoy recibiendo toneladas de is null :(
impresos. Pero si reemplazo el código con MyReference
(quitando dos líneas con MyReference y comentándolas con SoftReference) siempre obtengo OOM.
Como he entendido por el consejo, tener una referencia dura dentro de MyReference
no debería evitar que el objeto golpee ReferenceQueue
, ¿verdad?
¿sería posible fijar su código por lo que compila? Ej MiReferencia constructor toma el argumento referente Inflar y se supone que asignarlo a hardRef, pero hardRef es de un tipo totalmente diferente (ResourceThatMustBeClosed). además, se puede elaborar en qué Inflar sigue siendo necesaria una vez que tenemos ResourceThatMustBeClosed PS no sería tan necesitados si esta pregunta no tenía puntos de bonificación que se adjuntan:? P – mindas
he actualizado el código, y (con suerte) añadido una clara explicación de cómo funciona? Si no es así, que me haga saber ... –
Código se fija para que se compila. Sólo un tiro en una clase vacía, y añadir a la adecuada importaciones. –