Ich benutze eine Suchbibliothek, die darauf hinweist, dass das Such-Handle-Objekt geöffnet bleiben muss, damit der Abfrage-Cache genutzt werden kann. Im Laufe der Zeit habe ich beobachtet, dass der Cache aufgebläht wird (einige hundert MBs und wächst weiter) und OOMs begannen sich einzuschalten. Es gibt keine Möglichkeit, Grenzen dieses Cache zu erzwingen oder zu planen, wie viel Speicher er verwenden kann. Also habe ich den Grenzwert XMX erhöht, aber das ist nur eine vorübergehende Lösung für das Problem.Würde den SoftReference-Referenten korrekt abschließen
Schließlich denke ich, dieses Objekt zu einem Referent von java.lang.ref.SoftReference
machen. Wenn also der freie Speicher des Systems knapp wird, würde das Objekt losgelassen und bei Bedarf ein neues erstellt. Dies würde die Geschwindigkeit nach dem Neustart verringern, aber dies ist eine viel bessere Alternative als OOM zu treffen.
Das einzige Problem, das ich über SoftReferences sehe, ist, dass es keinen sauberen Weg gibt, ihre Referenten fertigzustellen. In meinem Fall muss ich das Such-Handle löschen, bevor ich es schließe, sonst könnte das System keine Dateideskriptoren mehr haben. Offensichtlich kann ich dieses Handle in ein anderes Objekt einfügen, einen Finalizer darauf schreiben (oder in eine ReferenceQueue/PhantomReference einhaken) und loslassen. Aber hey, jeder einzelne Artikel auf diesem Planeten rät davon ab, Finalizer zu verwenden, und insbesondere - gegen Finalizer zum Freigeben von Datei-Handles (z. B. Effektive Java ed. II, Seite 27.).
So bin ich etwas verwirrt. Sollte ich all diese Ratschläge sorgfältig ignorieren und weitermachen? Gibt es sonst noch Alternativen? Danke im Voraus.
EDIT # 1: Der folgende Text wurde nach dem Testen von Code hinzugefügt, wie von Tom Hawtin vorgeschlagen. Mir scheint, dass entweder der Vorschlag nicht funktioniert oder mir etwas fehlt. Hier ist der Code:
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++;
}
}
Wenn ich die Schnipsel oben mit -Xmx10m
und SoftReferences (wie im Code oben) laufen, ich bin immer Tonnen von is null :(
gedruckt. Aber wenn ich den Code durch MyReference
ersetze (zwei Zeilen mit MyReference auskommentieren und mit SoftReference auskommentieren), bekomme ich immer OOM.
Wie ich aus dem Rat verstanden, sollte harte Referenz innerhalb MyReference
nicht verhindern Objekt schlagen ReferenceQueue
, richtig?
Wäre es möglich, Ihren Code so zu reparieren, dass er kompiliert? ZB MyReference Konstruktor nimmt Bloat Referent Argument und soll es HardRef zuweisen, aber HardRef ist von einem völlig anderen Typ (ResourceThatMustBeClosed). Kannst du auch erklären, warum Bloat immer noch notwendig ist, wenn wir ResourceThatMustBeClosed haben? PS Ich wäre nicht so bedürftig, wenn diese Frage keine Bonuspunkte hätte: P – mindas
Ich habe den Code aktualisiert und (hoffentlich) ein klares hinzugefügt Erklärung, wie es funktioniert? Wenn nicht, lass es mich wissen ... –
Code ist fixiert, so dass es kompiliert.Schlecken Sie es einfach in eine leere Klasse, und fügen Sie die entsprechenden hinzu Importe. –