TBR v.io/x/jni: Delete local references when done with them
This *may* fix the syncslides crashes observed by afergan/kash. We can't
reproduce the problem in a test, however, but that could be due to a
more generous (or infinite) ref limit on desktops.
Together with sjr@, who correctly observed that we're overflowing a
local reference table, not global.
Note that it's still unclear if we really hit a case with 154 glob
results, or it may be something else going on. But this CL *is*
the right thing to do regardless.
Change-Id: I1250616818358760965495a03d3c972989a857ed
diff --git a/impl/google/namespace/jni.go b/impl/google/namespace/jni.go
index 5988465..2e19339 100644
--- a/impl/google/namespace/jni.go
+++ b/impl/google/namespace/jni.go
@@ -77,7 +77,7 @@
return jutil.NullObject, err
}
- retChan := make(chan jutil.Object, 100)
+ retChan := make(chan jutil.Object, 5)
go func() {
env, freeFunc := jutil.GetEnv()
defer freeFunc()
@@ -97,6 +97,9 @@
// The other side of the channel is responsible for deleting this
// global reference.
retChan <- jutil.NewGlobalRef(env, jGlobReply)
+ // Free up the local reference as it'll be auto-freed only when
+ // freeFunc() gets executed, which can burn us for big globs.
+ jutil.DeleteLocalRef(env, jGlobReply)
}
close(retChan)
}()
diff --git a/util/jni_wrapper.c b/util/jni_wrapper.c
index ffdb0f7..21c4a74 100644
--- a/util/jni_wrapper.c
+++ b/util/jni_wrapper.c
@@ -154,12 +154,16 @@
return (*env)->NewLocalRef(env, obj);
}
+void DeleteLocalRef(JNIEnv* env, jobject localRef) {
+ (*env)->DeleteLocalRef(env, localRef);
+}
+
jobject NewGlobalRef(JNIEnv* env, jobject obj) {
return (*env)->NewGlobalRef(env, obj);
}
void DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
- return (*env)->DeleteGlobalRef(env, globalRef);
+ (*env)->DeleteGlobalRef(env, globalRef);
}
jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
diff --git a/util/jni_wrapper.h b/util/jni_wrapper.h
index 7093b1c..2241c30 100644
--- a/util/jni_wrapper.h
+++ b/util/jni_wrapper.h
@@ -106,6 +106,9 @@
// Creates a new local reference to the object referred to by the obj argument.
jobject NewLocalRef(JNIEnv* env, jobject obj);
+// Deletes the local reference pointed to by localRef.
+void DeleteLocalRef(JNIEnv* env, jobject localRef);
+
// Creates a new global reference to the object referred to by the obj argument.
jobject NewGlobalRef(JNIEnv* env, jobject obj);
diff --git a/util/ref.go b/util/ref.go
index 3efb7ae..2b19433 100644
--- a/util/ref.go
+++ b/util/ref.go
@@ -28,13 +28,18 @@
C.DeleteGlobalRef(env.value(), obj.value())
}
-// Creates a new local reference that refers to the same object as obj. The
-// given obj may be a global or local reference. Returns null if ref refers
-// to null.
+// NewLocalRef creates a new local reference that refers to the same object
+// as obj. The given obj may be a global or local reference. Returns null if
+// ref refers to null.
func NewLocalRef(env Env, obj Object) Object {
return Object(uintptr(unsafe.Pointer(C.NewLocalRef(env.value(), obj.value()))))
}
+// DeleteLocalRef deletes the local reference pointed to by obj.
+func DeleteLocalRef(env Env, obj Object) {
+ C.DeleteLocalRef(env.value(), obj.value())
+}
+
// GoRef creates a new reference to the value addressed by the provided pointer.
// The value will remain referenced until it is explicitly unreferenced using
// goUnref().