我使用cglibMethodInterceptor
包装服务。在每次调用服务时,它都应该打开数据会话,将调用传递给服务,最后关闭会话。
但是,我注意到它在调用时行为不端Finalizer
。我得到以下堆栈跟踪:
java.lang.IllegalArgumentException: interface my.pkg.SomeInterface is not visible from class loader
at java.lang.reflect.Proxy.getProxyClass(Proxy.java:353)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
at my.pkg.ProxyFactory.create(ProxyFactory.java:68)
at my.pkg.SomeService.make(SomeService.java:181)
at my.pkg.SomeService$SessionWrappingInterceptor.intercept(SomeService.java:1275)
at my.pkg.SomeService$$EnhancerByCGLIB$$b58faf6a.finalize(<generated>)
at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:83)
at java.lang.ref.Finalizer.access$100(Finalizer.java:14)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:160)
我究竟做错了什么?我该如何解决?
当终结器最终选择要终结的对象(或 CGLIB 代理对象)时,垃圾收集器已确定您的对象无法访问并且即将被丢弃/收集。我们假设这不是唯一被收集的对象,事实上它过去可能使用过的其他对象(包括它们的类加载器)也被收集了。
您的问题中没有足够的信息来确定发生了什么,但我的一般猜测是您的 ProxyFactory 正在做的工作需要曾经可以被该类加载器访问但不再可以访问的类,可能是由于以下事实您正处于垃圾收集的最后阶段。
我经历了惨痛的教训才知道,处理 Finalize() 调用的代理是非常危险的。在大多数情况下,您的代理目标实际上不需要处理该调用,但如果需要处理该调用,请不要在代理处理程序中执行任何将创建、初始化或以其他方式创建对代理目标的引用的操作。 (例如,我的情况是一个按需加载的对象。当调用finalize()时,如果该对象之前没有被加载过,它会加载它并将值缓存在创建新的强引用链的地方,从而不允许代理类、它的类加载器以及它引用的许多其他类都会被收集。大量内存泄漏。)
我的建议(尽管已经很晚了)是禁止你的代理处理finalize()。可以为 CGLIB 的增强器提供 CallbackFilters 以指示不对 Finalize() 方法执行任何操作,或者如果您使用简单的 MethodInterceptor,则可以自行检查。
最后一条评论:小心回调过滤器 http://cglib.sourceforge.net/apidocs/net/sf/cglib/proxy/CallbackFilter.htmls。它们还可能导致内存泄漏,特别是如果它们来自与 CGLIB 不同的类加载器!您最终将得到 CGLIB 生成的对象,这些对象保留着不会被垃圾收集的 CallbackFilter 实例。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)