{"action":"created","issue":{"url":"https://api.github.com/repos/cglib/cglib/issues/80","repository_url":"https://api.github.com/repos/cglib/cglib","labels_url":"https://api.github.com/repos/cglib/cglib/issues/80/labels{/name}","comments_url":"https://api.github.com/repos/cglib/cglib/issues/80/comments","events_url":"https://api.github.com/repos/cglib/cglib/issues/80/events","html_url":"https://github.com/cglib/cglib/issues/80","id":160623315,"number":80,"title":"Memory leak caused by identical classes being generated","user":{"login":"asocaciu","id":771915,"avatar_url":"https://avatars.githubusercontent.com/u/771915?v=3","gravatar_id":"","url":"https://api.github.com/users/asocaciu","html_url":"https://github.com/asocaciu","followers_url":"https://api.github.com/users/asocaciu/followers","following_url":"https://api.github.com/users/asocaciu/following{/other_user}","gists_url":"https://api.github.com/users/asocaciu/gists{/gist_id}","starred_url":"https://api.github.com/users/asocaciu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/asocaciu/subscriptions","organizations_url":"https://api.github.com/users/asocaciu/orgs","repos_url":"https://api.github.com/users/asocaciu/repos","events_url":"https://api.github.com/users/asocaciu/events{/privacy}","received_events_url":"https://api.github.com/users/asocaciu/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":14,"created_at":"2016-06-16T09:58:43Z","updated_at":"2016-06-16T15:03:28Z","closed_at":null,"body":"We're having an issue where our spring-based JSF webapp throws an OOM after a few days (Spring 4.2.6 with cglib 3.2.2). I've tracked it down to the proxy classes that are generated for the Spring/JSF beans: instead of reusing the already generated cglib class definition, new ones are generated quite frequently. Since the classes themselves won't get garbage collected we run out of memory after a few days.\r\n\r\nI've created a small example (mirroring the way spring uses cglib internally) to reproduce the issue:\r\n```\r\nwhile (true) {\r\n            Enhancer enhancer = new Enhancer();\r\n            enhancer.setSuperclass(SampleClass.class);\r\n            enhancer.setCallbackFilter(new CallbackFilter() {\r\n                @Override\r\n                public int accept(Method method) {\r\n                    return 0;\r\n                }\r\n                @Override\r\n                public boolean equals(Object obj) {\r\n                    return true;\r\n                }\r\n\r\n                @Override\r\n                public int hashCode() {\r\n                    return 0;\r\n                }\r\n            });\r\n            enhancer.setInterfaces(new Class[]{SampleI.class});\r\n            enhancer.setCallback(new InvocationHandler() {\r\n                @Override\r\n                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\r\n                    if (method.getDeclaringClass() != Object.class\r\n                            && method.getReturnType() == String.class) {\r\n                        System.out.println(\"Hello cglib!\");\r\n                        return null;\r\n                    } else {\r\n                        throw new RuntimeException(\"Do not know what to do.\");\r\n                    }\r\n                }});\r\n            SampleClass proxy = (SampleClass) enhancer.create();\r\n            proxy.test(\"2\");\r\n            Thread.sleep(30);\r\n        }\r\n```\r\nSampleClass is just: \r\n```\r\npublic class SampleClass implements SampleI {\r\n\r\n    public String test(String s) {\r\n        return s;\r\n    }\r\n\r\n}\r\n```\r\nAfter every GC run, the cached generated classes are no longer used, instead new ones are generated. See attached shot from memory profiler\r\n![2016-06-16 11_51_00-cg - yourkit java profiler 2016 02-b38 - 64-bit](https://cloud.githubusercontent.com/assets/771915/16112709/e478987c-33b8-11e6-9f3c-8de1483c39cc.png)\r\n\r\n\r\nI've tracked this down to the LoadingCache and the use of a CallbackFilter on the Enhancer. The CallbackFilter is kept via WeakReference and used as part of the map key in the cache. If the filter is not referenced from outside it will be GC'd, so the entry in the cache won't be found any more.\r\n"},"comment":{"url":"https://api.github.com/repos/cglib/cglib/issues/comments/226512933","html_url":"https://github.com/cglib/cglib/issues/80#issuecomment-226512933","issue_url":"https://api.github.com/repos/cglib/cglib/issues/80","id":226512933,"user":{"login":"vlsi","id":213894,"avatar_url":"https://avatars.githubusercontent.com/u/213894?v=3","gravatar_id":"","url":"https://api.github.com/users/vlsi","html_url":"https://github.com/vlsi","followers_url":"https://api.github.com/users/vlsi/followers","following_url":"https://api.github.com/users/vlsi/following{/other_user}","gists_url":"https://api.github.com/users/vlsi/gists{/gist_id}","starred_url":"https://api.github.com/users/vlsi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vlsi/subscriptions","organizations_url":"https://api.github.com/users/vlsi/orgs","repos_url":"https://api.github.com/users/vlsi/repos","events_url":"https://api.github.com/users/vlsi/events{/privacy}","received_events_url":"https://api.github.com/users/vlsi/received_events","type":"User","site_admin":false},"created_at":"2016-06-16T15:03:28Z","updated_at":"2016-06-16T15:03:28Z","body":"> It's a bad idea to have a key whose equals/hashcode can change\r\n\r\nIt does not change over time. Hash code is cached at instantiation, and equals is just equals.\r\n\r\n> Alternately, could something sweep through the cache [perhaps on future writes?] and remove entries that are no longer useful\r\n\r\nThat enhancement makes sense."}}
{"actor":{"display_login":"vlsi"}}