Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Write-to-disk cache via WeakReferences?

Reply
Thread Tools

Write-to-disk cache via WeakReferences?

 
 
Paul J. Lucas
Guest
Posts: n/a
 
      07-23-2005
So the idea is to use WeakReferences to objects. When the GC
decides to GC said objects, I'd like a thread to be notified
via a ReferenceQueue that the objects are about to be GC'd. The
thread can then write them out to disk. The upshot of all this
would be to implement a disk cache for objects.

The problem is, in reading the documentation for WeakReference,
that all WeakReferences are cleared prior to being enqueued
onto ReferenceQueues. That means the code that does either the
poll() or remove() will always get a reference with null for
the referrent value of get().

That's annoying. Ideally, I want the thread to be able to get
at the object just before it's GC'd so it can be written out to
disk.

So is it possible to do something like I want (i.e., be given a
reference to an object about to be GC'd so I can do one last
thing with it)? If so, how?

- Paul
 
Reply With Quote
 
 
 
 
Thomas Hawtin
Guest
Posts: n/a
 
      07-23-2005
Paul J. Lucas wrote:
>
> The problem is, in reading the documentation for WeakReference,
> that all WeakReferences are cleared prior to being enqueued
> onto ReferenceQueues. That means the code that does either the
> poll() or remove() will always get a reference with null for
> the referrent value of get().


Two options.

Use a proxy interface to your resource. Create a class that extends
WeakReference with the weak reference to the proxy and a strong
reference to the resource. Sometime after the Proxy is collected, the
WeakReference pops up on the reference queue, and you can get the strong
reference to the resource from that.

Proxy ----> Resource
^ ^
| |
{weak}| |{strong}
| |
Ref extends |
WeakReference<Proxy> -+

Alternatively use a finaliser. When finalize is called, resurrect the
resource by putting it on a queue. Have a thread pulling from the queue
and saving to disc.

(Notes about finalisers: It's best to put the finalize method on a guard
object with a bidirectional reference to the resource, as finalize
doesn't play nicely with inheritance. Certainly never delcare finalize
as anything other than protected and throws Throwable, and always call
the super with try/finally even if it is not overriden by a superclass
(yet). You shouldn't do much in the finaliser as you will block the
finalise thread(s) work. An object will finalise only once. It's your
responsibility to make sure finalisers are thread-safe, typically by
synchronising all methods. Finalisers have a bad reputation and you
could get yourself into some pointless conversations.)

Tom Hawtin
--
Unemployed English Java programmer
 
Reply With Quote
 
 
 
 
Paul J. Lucas
Guest
Posts: n/a
 
      07-24-2005
Thomas Hawtin <(E-Mail Removed)> wrote:

> Use a proxy interface to your resource. Create a class that extends
> WeakReference with the weak reference to the proxy and a strong
> reference to the resource. Sometime after the Proxy is collected, the
> WeakReference pops up on the reference queue, and you can get the strong
> reference to the resource from that.
>
> Proxy ----> Resource
> ^ ^
> | |
> {weak}| |{strong}
> | |
> Ref extends |
> WeakReference<Proxy> -+


What is the upper, horizontal arrow? A strong or weak
references?

BTW: should it be a WeakReference or a SoftReference?

> Alternatively use a finaliser. When finalize is called, resurrect the
> resource by putting it on a queue. Have a thread pulling from the queue
> and saving to disc.


The problem with that approach is that it's "intrusive" into the
class of object that is the resource, i.e., you can't do this
with any old object: it has to be one that has a finalizer that
does the right thing.

- Paul
 
Reply With Quote
 
Thomas Hawtin
Guest
Posts: n/a
 
      07-24-2005
Paul J. Lucas wrote:
> Thomas Hawtin <(E-Mail Removed)> wrote:
>
>
>>Use a proxy interface to your resource. Create a class that extends
>>WeakReference with the weak reference to the proxy and a strong
>>reference to the resource. Sometime after the Proxy is collected, the
>>WeakReference pops up on the reference queue, and you can get the strong
>>reference to the resource from that.
>>
>> Proxy ----> Resource
>> ^ ^
>> | |
>> {weak}| |{strong}
>> | |
>> Ref extends |
>>WeakReference<Proxy> -+

>
>
> What is the upper, horizontal arrow? A strong or weak
> references?


Strong. You don't want the resource disappearing while you still have
the proxy alive.

> BTW: should it be a WeakReference or a SoftReference?


Almost certainly soft. Weak references are useful if the cache is
extremely marginal (and then the cache will probably only make
significant differences in microbenchmarks). You might want to use a
weak reference if you know it is unlikely that the resource will be used
again anytime soon (usually a poor bet). I just stuck with the original
choice.

>>Alternatively use a finaliser. When finalize is called, resurrect the
>>resource by putting it on a queue. Have a thread pulling from the queue
>>and saving to disc.

>
>
> The problem with that approach is that it's "intrusive" into the
> class of object that is the resource, i.e., you can't do this
> with any old object: it has to be one that has a finalizer that
> does the right thing.


Yup, although you can put the finaliser (guard) on a proxy.

Tom Hawtin
--
Unemployed English Java programmer
 
Reply With Quote
 
Paul J. Lucas
Guest
Posts: n/a
 
      07-24-2005
Thomas Hawtin <(E-Mail Removed)> wrote:
> Paul J. Lucas wrote:


> > What is the upper, horizontal arrow? A strong or weak
> > references?

>
> Strong. You don't want the resource disappearing while you still have
> the proxy alive.


But if the class derived from WeakReference itself has a strong
reference to the object, why does the proxy object need one
also?

I would think that the proxy object could be a class like:

class Sacrifice {
// yes, empty
}

and the class derived from WeakReference has a weak reference to
it. The only reason for having a Sacrifice object is to be
sacrificed to the GC: when the GC wants to reclaim it, the
class derived from weak referernce referring to it gets
enqueued, i.e., it only serves as the trigger mechanism. The
class derived from WeakReference has its own hard reference to
the object.

Or am I missing something?

- Paul
 
Reply With Quote
 
Thomas Hawtin
Guest
Posts: n/a
 
      07-24-2005
Paul J. Lucas wrote:
>
> But if the class derived from WeakReference itself has a strong
> reference to the object, why does the proxy object need one
> also?
>
> I would think that the proxy object could be a class like:
>
> class Sacrifice {
> // yes, empty
> }
>
> and the class derived from WeakReference has a weak reference to
> it. The only reason for having a Sacrifice object is to be
> sacrificed to the GC: when the GC wants to reclaim it, the
> class derived from weak referernce referring to it gets
> enqueued, i.e., it only serves as the trigger mechanism. The
> class derived from WeakReference has its own hard reference to
> the object.


I think I'm being confusing with my proxies and guards. The guards are
for use with finalisers and aren't important here.

The situation in code looks something like this (only with better names):

public class Resource {
public void doStuff() { ... }
}
public class Proxy {
private final Resource target;
Proxy(Resource target) {
if (target == null) {
throw new NullPointerException();
}
this.target = target;
}
public void doStuff() {
target.doStuff();
}
}
class Ref extends Reference<Proxy> {
private final Resource resource;
public Ref(Proxy proxy, Resource resource) {
super(proxy);
this.resource = resource;
}
Resource getResource() {
return resource;
}
}
class Saver implements Runnable {
...
public void run() {
for (; {
Ref ref = (Ref)queue.remove();
saveToDisk(ref.getResource());
}
}
}

The client code uses Proxy rather than Resource.

Tom
--
Unemployed English Java programmer
 
Reply With Quote
 
Paul J. Lucas
Guest
Posts: n/a
 
      07-25-2005
Thomas Hawtin <(E-Mail Removed)> wrote:

> The situation in code looks something like this (only with better names):
>
> public class Resource {
> public void doStuff() { ... }
> }
> public class Proxy {
> private final Resource target;
> Proxy(Resource target) {
> if (target == null) {
> throw new NullPointerException();
> }
> this.target = target;
> }
> public void doStuff() {
> target.doStuff();
> }
> }
> class Ref extends Reference<Proxy> {
> private final Resource resource;
> public Ref(Proxy proxy, Resource resource) {
> super(proxy);
> this.resource = resource;
> }
> Resource getResource() {
> return resource;
> }
> }
> class Saver implements Runnable {
> ...
> public void run() {
> for (; {
> Ref ref = (Ref)queue.remove();
> saveToDisk(ref.getResource());
> }
> }
> }


Where did the SoftReference go?
You never create/pass a ReferenceQueue anywhere.
What about my code below?

- Paul


public interface StrongReference {
Object getAndClearStrong();
}

public class SoftStrongReference extends SoftReference
implements StrongReference {

public SoftStrongReference( Object referrent, ReferenceQueue refQ ) {
super( new Sacrifice(), refQ );
m_referrent = referrent;
}

public Object getAndClearStrong() {
final Object temp = m_referrent;
m_referrent = null;
return temp;
}

private static final class Sacrifice {
}

private Object m_referrent;
}

public interface ObjectSaver {
void save( Object obj );
}

public class ReferenceQueueManager extends Thread {

public ReferenceQueueManager( ObjectSaver saver ) {
setDaemon( true );
m_saver = saver;
m_refQ = new ReferenceQueue();
}

public void kill() {
m_killed = true;
interrupt();
}

public void run() {
while ( !m_killed ) {
try {
final StrongReference ref = (StrongReference)m_refQ.remove();
m_saver.save( ref.getAndClearStrong() );
}
catch ( InterruptedException e ) {
// do nothing
}
}
}

private boolean m_killed;
private final ObjectSaver m_saver;
private final ReferenceQueue m_refQ;
}
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
ASP.NET Cache vs Window System Cache Sergey via DotNetMonster.com ASP .Net 0 11-15-2006 03:33 PM
no-cache - need to reload page from server and not the cache John HTML 2 10-29-2006 05:35 PM
client-side cache vs server-side cache vs ajax vs asp.net callback =?Utf-8?B?b25l?= ASP .Net 1 03-08-2006 12:25 PM
Page.Cache vs HttpContext.Current.Cache DesignerX ASP .Net 5 01-20-2004 10:55 PM
Cache::Cache Stale Segments Jeff Nokes Perl 0 09-30-2003 04:34 PM



Advertisments