Fix AutoBean VM memory leak due to circular references between the
ProxyAutoBean, ShimHandler, and WeakReference.
Issue 6193.
http://gwt-code-reviews.appspot.com/1448803
Patch by: bobv
Review by: tbroyer, rjrjr
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10201 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java b/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java
index cdf61dc..d52579d 100644
--- a/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java
+++ b/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java
@@ -15,14 +15,15 @@
*/
package com.google.web.bindery.autobean.vm.impl;
+import com.google.gwt.core.client.impl.WeakMapping;
import com.google.web.bindery.autobean.shared.AutoBean;
import com.google.web.bindery.autobean.shared.AutoBeanFactory;
import com.google.web.bindery.autobean.shared.AutoBeanUtils;
import com.google.web.bindery.autobean.shared.AutoBeanVisitor;
import com.google.web.bindery.autobean.shared.impl.AbstractAutoBean;
import com.google.web.bindery.autobean.vm.Configuration;
-import com.google.gwt.core.client.impl.WeakMapping;
+import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -66,7 +67,7 @@
Class<?>... extraInterfaces) {
Class<?>[] intfs;
if (extraInterfaces == null) {
- intfs = new Class<?>[]{intf};
+ intfs = new Class<?>[] {intf};
} else {
intfs = new Class<?>[extraInterfaces.length + 1];
intfs[0] = intf;
@@ -116,7 +117,25 @@
private final Class<T> beanType;
private final Configuration configuration;
private final Data data;
- private final T shim;
+ /**
+ * Because the shim and the ProxyAutoBean are related through WeakMapping, we
+ * need to ensure that the ProxyAutoBean doesn't artificially extend the
+ * lifetime of the shim. If there are no external references to the shim, it's
+ * ok if it's deallocated, since it has no interesting state.
+ *
+ * <pre>
+ *
+ * ----------------- --------------
+ * | ProxyAutoBean | | Shim |
+ * | | <------+-bean |
+ * | shim-+---X--->|____________|
+ * |_______________| ^
+ * ^ |
+ * | X
+ * |______ WeakMapping ___|
+ * </pre>
+ */
+ private WeakReference<T> shim;
// These constructors mirror the generated constructors.
@SuppressWarnings("unchecked")
@@ -125,7 +144,6 @@
this.beanType = (Class<T>) beanType;
this.configuration = configuration;
this.data = calculateData(beanType);
- this.shim = createShim();
}
@SuppressWarnings("unchecked")
@@ -135,12 +153,16 @@
this.beanType = (Class<T>) beanType;
this.configuration = configuration;
this.data = calculateData(beanType);
- this.shim = createShim();
}
@Override
public T as() {
- return shim;
+ T toReturn = shim == null ? null : shim.get();
+ if (toReturn == null) {
+ toReturn = createShim();
+ shim = new WeakReference<T>(toReturn);
+ }
+ return toReturn;
}
public Configuration getConfiguration() {
@@ -241,7 +263,7 @@
Object value;
try {
getter.setAccessible(true);
- value = getter.invoke(shim);
+ value = getter.invoke(as());
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {