WeakHashMap question

M

mitch gart

In our program we create a huge number of objects of a class,
call it Apple. Apples are immutable. Many of them have the same
values: in more than 90% of the cases when we are constructing a new
apple2, apple2.equals(apple1) for some other object apple1 which was
already created.

Our program is running into memory problems and I'd like to replace
the constructor for Apple with a factory method which checks to see
if there is already an existing object, and if so returns a reference
to that, otherwise constructs a new one if really needed.

This seems like a good use of WeakHashMap because we would like to
maintain a list of existing objects, but allow them to be garbage
collected when the last reference goes away. However in thinking about
the details I have a question.

Suppose when we put an object into the WeakHashMap we do

map.put(apple2, apple2);

and when we look for one we do

if (map.containsKey(apple2)) {
return map.get(apple2);
} else {
return new Apple(...)
}

It seems like that would work, except that the values in a
WeakHashMap (as opposed to the keys) are kept as strong references,
not weak references. It seems like doing this would make it so
no apples were ever garbage collected.

Any ideas how to do this? Thanks,

- Mitch
 
J

John C. Bollinger

mitch said:
In our program we create a huge number of objects of a class,
call it Apple. Apples are immutable. Many of them have the same
values: in more than 90% of the cases when we are constructing a new
apple2, apple2.equals(apple1) for some other object apple1 which was
already created.

Our program is running into memory problems and I'd like to replace
the constructor for Apple with a factory method which checks to see
if there is already an existing object, and if so returns a reference
to that, otherwise constructs a new one if really needed.

This seems like a good use of WeakHashMap because we would like to
maintain a list of existing objects, but allow them to be garbage
collected when the last reference goes away. However in thinking about
the details I have a question.

Suppose when we put an object into the WeakHashMap we do

map.put(apple2, apple2);

and when we look for one we do

if (map.containsKey(apple2)) {
return map.get(apple2);
} else {
return new Apple(...)
}

It seems like that would work, except that the values in a
WeakHashMap (as opposed to the keys) are kept as strong references,
not weak references. It seems like doing this would make it so
no apples were ever garbage collected.

Any ideas how to do this? Thanks,

If you want to do it via a WeakHashMap (which seems a reasonable idea to
me) then you need to use keys that are distinct from (and do not
directly or indirectly reference) the values. The value may reference
they key, but not vise versa. If there is a unique identifier String of
some sort for each Apple then that would be ideal. A second alternative
would be a proto-object -- a lightweight, immutable object containing
sufficient state to uniquely identify an Apple, and exposing appropriate
equals() and hashCode() methods. You could even use such an object as a
constructor parameter in those cases where it turns out you do need to
construct a new Apple.

If you don't like that then I imagine you could work out how to write
your own WeakHashSet with the behavior you want. Use the WeakHashMap
source for reference if you like.


John Bollinger
(e-mail address removed)
 
A

Adam Jenkins

John said:
mitch said:
In our program we create a huge number of objects of a class,
call it Apple. Apples are immutable. Many of them have the same
values: in more than 90% of the cases when we are constructing a new
apple2, apple2.equals(apple1) for some other object apple1 which was
already created.

Our program is running into memory problems and I'd like to replace
the constructor for Apple with a factory method which checks to see
if there is already an existing object, and if so returns a reference
to that, otherwise constructs a new one if really needed.
[snip]
If you want to do it via a WeakHashMap (which seems a reasonable idea to
me) then you need to use keys that are distinct from (and do not
directly or indirectly reference) the values.

Actually WeakHashMap is the wrong class for the job. The problem is
that in a WeakHashMap, it is the *key* which has a weak reference to it,
not the value. This means that an entry can be removed when the last
reference to the *key* goes away, even if there are still strong
references to the value.

Also, for memory cache purposes, a SoftReference is more appropriate
than a WeakReference. The library spec recommends that GCs put off
collecting soft referenced objects until the system runs short on
memory, whereas weak referenced objects are encouraged to be collected
more eagerly. If the point is to avoid recreating identical objects,
then the SoftReference behaviour is what is wanted.

So, what you really want is a Map where the *values* are soft
referenced. This way, an entry is only eligable for removal when there
are no references to the value, and entries are likely to stay in memory
as long as possible, increasing the likelihood that they'll be reused.
The Jakarta Commons Collections package has a nice ReferenceMap class
which lets you specify what type of references to use for both the keys
and values. For your use, you'd create

Map appleCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);

You can get the package here:

http://jakarta.apache.org/commons/collections.html

Adam
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,743
Latest member
WoodrowMea

Latest Threads

Top