I have an odd situation.
I have a simple flyweight factory that allows me to reuse instances that are equal() in a graph of objects.
When I serialize the root object, with and without use flyweight, to measure its benefit, I go from 2,014,169 bytes with a new object for each reference, down to 1,680,865. Okay, that is fine.
BUT, when I look at this object's retained size in a heap dump in jvisualvm, I always see 6,807,832.
How can it be? Surely if in one case I have multiple instances of the same object, they each take up memory. Retained size should be the amount that would be recovered from GC. I would think that would be more without using the flyweight factory to recycle instances. If I wasn't seeing the benefit in serialization, I'd think it was a bug in the flyweight factory, but I can't see how it'd only work for serialization.
Right now I'm a bit perplexed.
Using the flyweight factory, you pass new instances through a check to see if a reference can be reused instead:
map.put(key, flyweightFactory.get(new MyClass()));
If not using the flyweight, store the new object every time:
map.put(key, new MyClass());
And for reference, here is the flyweight factory class:
/**
*
* Provides simple object reuse a la the flyweight pattern. Not thread safe.
*
* @author sigmund.segfeldt
*
* @param <A> type to be stored in the flyweight factory
*/
public class FlyweightFactory<A> {
private final Map<A, A> flyweights = new HashMap<>();
private int reuses = 0;
/**
*
* returns an instance of A, which is equal to the instance provided, ensuring
* that the same reference is always supplied for any such equal objects.
*
* @param instance
* @return a reference to an equal to instance, possibly instance itself
*/
public A get(A instance) {
A flyweight;
if (flyweights.containsKey(instance)) {
flyweight = flyweights.get(instance);
++reuses;
} else {
flyweights.put(instance, instance);
flyweight = instance;
}
return flyweight;
}
/**
*
* @return the size of the flyweight factory; i.e. the number of distinct objects held
*/
public int size() {
return flyweights.size();
}
/**
*
* @return number of times a flyweight has been reused, purely for statistics to see how beneficial flyweight is (without
* taking into consideration the size of reused objects, of course).
*/
public int reuses() {
return reuses;
}
@Override
public String toString() {
return "FlyweightFactory[size " + size() + ", reuses=" + reuses() + "]";
}
}