From b5c478ef5d3c856133dd88645cf71d92f9bfd622 Mon Sep 17 00:00:00 2001 From: Jairo Barros Date: Mon, 1 Apr 2024 19:56:21 -0700 Subject: [PATCH] Adding env.DeleteGlobalRefCache method to avoid memory leak after env instance gets out of scope --- jnigi.go | 9 +++++++++ jnigi_test.go | 20 ++++++++++++++++++++ jnigi_test_c_callback.go | 1 + 3 files changed, 30 insertions(+) diff --git a/jnigi.go b/jnigi.go index 742468b..c4554db 100644 --- a/jnigi.go +++ b/jnigi.go @@ -1909,6 +1909,15 @@ func (j *Env) GetUTF8String() *ObjectRef { return utf8 } +// DeleteGlobalRefCache deletes all globalRef that are in classCache. This methods should +// be called when an instance of *Env gets out of scope +func (j *Env) DeleteGlobalRefCache() { + for _, v := range j.classCache { + deleteGlobalRef(j.jniEnv, jobject(v)) + } + j.classCache = make(map[string]jclass) +} + // StackTraceElement is a struct holding the contents of java.lang.StackTraceElement // for use in a ThrowableError. type StackTraceElement struct { diff --git a/jnigi_test.go b/jnigi_test.go index a3c7db0..c6d82bb 100644 --- a/jnigi_test.go +++ b/jnigi_test.go @@ -35,6 +35,7 @@ func TestAll(t *testing.T) { PTestCast(t) PTestNonVirtual(t) PTestRegisterNative(t) + PTestDeleteGlobalRefCache(t) PTestDestroy(t) } @@ -378,6 +379,7 @@ func PTestGetJVM(t *testing.T) { } func PTestDestroy(t *testing.T) { + env.DeleteGlobalRefCache() err := jvm.Destroy() if err != nil { t.Fatalf("DestroyJVM failed %s", err) @@ -595,6 +597,24 @@ func PTestRegisterNative(t *testing.T) { } } +func PTestDeleteGlobalRefCache(t *testing.T) { + str, err := env.NewObject("java/lang/String", []byte("hello world")) + if err != nil { + t.Fatal(err) + } + defer env.DeleteLocalRef(str) + var goBytes []byte + if err := str.CallMethod(env, "getBytes", &goBytes); err != nil { + t.Fatal(err) + } + + env.DeleteGlobalRefCache() + + if !assert.Empty(t, env.classCache) { + t.Fail() + } +} + func toGoStr(t *testing.T, o *ObjectRef) string { var goBytes []byte if err := o.CallMethod(env, "getBytes", &goBytes); err != nil { diff --git a/jnigi_test_c_callback.go b/jnigi_test_c_callback.go index 54a4c88..9bde8dc 100644 --- a/jnigi_test_c_callback.go +++ b/jnigi_test_c_callback.go @@ -17,6 +17,7 @@ import "C" //export go_callback_Greet func go_callback_Greet(jenv unsafe.Pointer, jobj uintptr, arg_0 uintptr) uintptr { env := WrapEnv(jenv) + defer env.DeleteGlobalRefCache() env.ExceptionHandler = ThrowableToStringExceptionHandler strArgRef := WrapJObject(arg_0, "java/lang/String", false)