使用flyweight模式后,visualvm保持大小相同

时间:2016-10-07 18:30:50

标签: java memory profiling visualvm flyweight-pattern

我有一个奇怪的情况。

我有一个简单的flyweight工厂,允许我在对象图中重用等于()的实例。

当我使用和不使用flyweight来序列化根对象时,为了测量它的好处,我从2,014,169字节开始,为每个引用添加一个新对象,下降到1,680,865。好的,没关系。

但是,当我在jvisualvm的堆转储中查看此对象的保留大小时,我总是看到6,807,832。

怎么可能?当然,如果在一种情况下我有同一个对象的多个实例,它们每个都会占用内存。保留的大小应该是从GC中回收的量。我认为没有使用flyweight工厂来回收实例会更多。如果我没有看到序列化的好处,我认为它是flyweight工厂中的一个错误,但我不知道它是如何仅用于序列化的。

现在我有点困惑。

使用flyweight工厂,您可以通过检查传递新实例,以查看是否可以重复使用引用:

map.put(key, flyweightFactory.get(new MyClass()));

如果不使用flyweight,请每次都存储新对象:

map.put(key, new MyClass());

作为参考,这里是flyweight工厂类:

/**
 * 
 * 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() + "]";
    }
}

1 个答案:

答案 0 :(得分:0)

所以问题是我没有发布轻量级工厂本身。它不是从根对象引用的,但是通过保持对flyweight对象的其他引用,它们不会计入保留的大小。

一旦我的测试用例被修复,并且除了通过根对象之外没有对flyweights的引用,保留的大小上升到9.2mb with flyweight,10.3mb没有通过flyweights回收相同的实例。

我被对象的保留大小所欺骗; 6.8mb只是容器对象和引用的开销(假设键也是flyweights)。我没有想到我的飞锤甚至没有被计算在内。

这实际上非常有用。这是一个有用的错误!我需要查看容器本身,看看我是否能从使用enummaps替换hashmaps中获益(10mb可能看起来不多,但我的目标是占用空间小!)

顺便说一句,执行GC并没有任何区别,无论是否有飞重。

感谢您的输入人员。