On 18.05.16 09:10, Jochen Theodorou wrote:
     private static class GlobalClassSet {

         //private final ManagedLinkedList<ClassInfo> items = new
ManagedLinkedList<ClassInfo>(weakBundle);
         private final WeakHashMap<Class,WeakReference<ClassInfo>> items
= new WeakHashMap<Class,WeakReference<ClassInfo>>();

would be actually interesting to keep the list and see if it can still garbage collect

Looks like it can. (As I would have expected because ClassInfo.remove(clazz) did not touch that list before and that was sufficient to get GC on-the-fly provided you also do Introspector.flushFromCaches(clazz) ):

--
    private static class GlobalClassSet {

private final ManagedLinkedList<ClassInfo> itemsList = new ManagedLinkedList<ClassInfo>(weakBundle); private final WeakHashMap<Class,WeakReference<ClassInfo>> itemsMap = new WeakHashMap<Class,WeakReference<ClassInfo>>();

        public int size(){
            return values().size();
        }

        public int fullSize(){
            return values().size();
        }

        public Collection<ClassInfo> values(){
            synchronized(itemsList){
                return Arrays.asList(itemsList.toArray(new ClassInfo[0]));
            }
        }

        public void add(ClassInfo value){
            synchronized(itemsList) {
                itemsList.add(value);
            }
            synchronized(itemsMap) {
itemsMap.put(value.klazz, new WeakReference<ClassInfo>(value));
            }
        }

        public ClassInfo get(Class cls) {
            WeakReference<ClassInfo> ref;
            synchronized(itemsMap) {
                ref = itemsMap.get(cls);
            }
            ClassInfo info;
            if (ref == null) {
//System.out.println("ClassInfo Ref is null: " + cls.getName());
                info = new ClassInfo(cls);
                synchronized (itemsMap) {
                    itemsMap.put(cls, new WeakReference<ClassInfo>(info));
                }
                return info;
            }
            info = ref.get();
            if (info == null) {
//System.out.println("ClassInfo is null: " + cls.getName());
                info = new ClassInfo(cls);
                itemsMap.put(cls, new WeakReference<ClassInfo>(info));
                return info;
            }
            return info;
        }

    }
--

$ java -XX:MaxMetaspaceSize=64m -Xmx512m -cp .:groovy-2.5.0-SNAPSHOT.jar ClassGCTester -cp filling/ -parent tester -classes GroovyFilling
(does a Introspector.flushFromCaches(clazz) for each loaded class)

Secs Test classes Metaspace/PermGen Heap Load time Create time Run time Cleanup time #loaded #remaining used committed used committed average average average average 0 1 1 6.3m 6.5m 13.4m 245.5m 0.890ms 14.308ms 0.026168ms 0.019285ms 1 435 435 8.9m 10.1m 22.1m 245.5m 0.365ms 1.825ms 0.000064ms 0.000009ms 2 1202 1202 11.9m 14.6m 66.1m 245.5m 0.280ms 1.314ms 0.000024ms 0.000001ms 3 2197 2197 15.7m 20.4m 83.8m 309.5m 0.240ms 1.070ms 0.000010ms 0.000001ms 4 3247 966 11.0m 16.8m 16.5m 242.0m 0.226ms 0.959ms 0.000006ms 0.000000ms 5 4396 2115 15.4m 20.3m 44.5m 238.0m 0.208ms 0.886ms 0.000005ms 0.000000ms 6 5415 3134 19.3m 26.0m 54.4m 235.5m 0.202ms 0.863ms 0.000009ms 0.000000ms 7 6458 667 9.8m 18.0m 94.7m 266.5m 0.203ms 0.839ms 0.000003ms 0.000000ms 8 7550 1759 14.0m 21.4m 122.0m 268.5m 0.198ms 0.821ms 0.000003ms 0.000000ms 9 8748 2957 18.6m 25.9m 46.3m 268.5m 0.191ms 0.799ms 0.000003ms 0.000000ms
[...]

Very interesting because the list contains references to the class and yet it can be garbage collected on-the-fly... Maybe that could help to find a solution?

Alain

Reply via email to