我使用cglib MethodInterceptor来包装服务。在对服务的每次调用中,它都应该打开数据会话,将调用传递给服务,最后关闭会话。
然而,我注意到它在从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)我做错了什么?我怎么解决它呢?
发布于 2011-08-13 06:05:03
当终结器最终选择您的对象(或您的CGLIB代理对象)进行终结器时,垃圾收集器已经确定您的对象是不可访问的,并且即将被丢弃/收集。让我们假设这不是唯一被收集的对象,事实上,它过去可能使用的其他对象(包括它们的类加载器)也已经被收集了。
你的问题中没有足够的信息来确定发生了什么,但我一般猜测你的ProxyFactory正在做的工作需要一些过去可以被这个类加载器访问但现在不能访问的类,这可能是因为你处于垃圾收集的最后阶段。
我知道处理finalize()调用的代理是非常危险的。在大多数情况下,您的代理目标确实不需要处理该调用,但如果它需要,请不要在您的代理处理程序中执行任何创建、初始化或以其他方式创建对代理目标的引用的操作。(例如,我的案例是一个按需加载对象。当调用finalize()时,如果该对象以前没有被加载过,它将加载它并在某个地方缓存创建了一个新的强引用链的值,从而禁止收集代理类、它的类加载器以及它引用的许多其他类。大量内存泄漏。)
我的建议(虽然有点晚了)是不允许您的代理处理finalize()。CGLIB的增强器可以被赋予CallbackFilters,以指示不使用finalize()方法做任何事情,或者如果您使用简单的MethodInterceptor,您可以自己检查。
最后一点:小心使用CallbackFilter,它们也会导致内存泄漏,特别是当它们来自不同的类加载器时!您最终将得到CGLIB生成的对象,这些对象保留不会被垃圾收集的CallbackFilter实例。
https://stackoverflow.com/questions/6517348
复制相似问题