2626#include " util.hpp"
2727#include " jni_util/java_method.hpp"
2828#include " jni_util/java_class.hpp"
29- #include " jni_util/java_global_ref .hpp"
29+ #include " jni_util/java_global_weak_ref .hpp"
3030#include " jni_util/jni_utils.hpp"
3131#include " jni_util/java_exception_thrower.hpp"
3232
@@ -132,16 +132,26 @@ JNIEXPORT void JNICALL Java_io_realm_internal_OsRealmConfig_nativeSetSchemaConfi
132132 static JavaMethod run_migration_callback_method (
133133 env, get_shared_realm_class (env), " runMigrationCallback" ,
134134 " (JLio/realm/internal/OsRealmConfig;Lio/realm/internal/SharedRealm$MigrationCallback;J)V" , true );
135- JavaGlobalRef j_config_ref (env, j_config, true );
136- JavaGlobalRef j_migration_callback_ref (env, j_migration_callback, true );
137- config.migration_function = [j_config_ref, j_migration_callback_ref](SharedRealm old_realm,
135+ // weak ref to avoid leaks caused by circular refs.
136+ JavaGlobalWeakRef j_config_weak (env, j_config);
137+ JavaGlobalWeakRef j_migration_cb_weak (env, j_migration_callback);
138+ // TODO: It would be great if we can use move constructor in the lambda capture which was introduced in
139+ // c++14. But sadly it seems to be a bug with gcc 4.9 to support it.
140+ config.migration_function = [j_migration_cb_weak, j_config_weak](SharedRealm old_realm,
138141 SharedRealm realm, Schema&) {
139142 JNIEnv* env = JniUtils::get_env (false );
140143 // Java needs a new pointer for the SharedRealm life control.
141144 SharedRealm* new_shared_realm_ptr = new SharedRealm (realm);
142- env->CallStaticVoidMethod (get_shared_realm_class (env), run_migration_callback_method,
143- reinterpret_cast <jlong>(new_shared_realm_ptr), j_config_ref.get (),
144- j_migration_callback_ref.get (), old_realm->schema_version ());
145+ JavaGlobalRef config_global = j_config_weak.global_ref (env);
146+ if (!config_global) {
147+ return ;
148+ }
149+
150+ j_migration_cb_weak.call_with_local_ref (env, [&](JNIEnv* env, jobject obj) {
151+ env->CallStaticVoidMethod (get_shared_realm_class (env), run_migration_callback_method,
152+ reinterpret_cast <jlong>(new_shared_realm_ptr), config_global.get (), obj,
153+ old_realm->schema_version ());
154+ });
145155 TERMINATE_JNI_IF_JAVA_EXCEPTION_OCCURRED (env);
146156 };
147157 }
@@ -162,13 +172,17 @@ JNIEXPORT void JNICALL Java_io_realm_internal_OsRealmConfig_nativeSetCompactOnLa
162172 if (j_compact_on_launch) {
163173 static JavaClass compact_on_launch_class (env, " io/realm/CompactOnLaunchCallback" );
164174 static JavaMethod should_compact (env, compact_on_launch_class, " shouldCompact" , " (JJ)Z" );
165- JavaGlobalRef java_compact_on_launch_ref (env, j_compact_on_launch);
175+ // weak ref to avoid leaks caused by circular refs.
176+ JavaGlobalWeakRef java_compact_on_launch_weak (env, j_compact_on_launch);
166177
167- config.should_compact_on_launch_function = [java_compact_on_launch_ref ](uint64_t totalBytes,
178+ config.should_compact_on_launch_function = [java_compact_on_launch_weak ](uint64_t totalBytes,
168179 uint64_t usedBytes) {
169180 JNIEnv* env = JniUtils::get_env (false );
170- bool result = env->CallBooleanMethod (java_compact_on_launch_ref.get (), should_compact,
171- static_cast <jlong>(totalBytes), static_cast <jlong>(usedBytes));
181+ bool result = false ;
182+ java_compact_on_launch_weak.call_with_local_ref (env, [&](JNIEnv* env, jobject obj) {
183+ result = env->CallBooleanMethod (obj, should_compact, static_cast <jlong>(totalBytes),
184+ static_cast <jlong>(usedBytes));
185+ });
172186 TERMINATE_JNI_IF_JAVA_EXCEPTION_OCCURRED (env);
173187 return result;
174188 };
@@ -194,15 +208,22 @@ JNIEXPORT void JNICALL Java_io_realm_internal_OsRealmConfig_nativeSetInitializat
194208 static JavaMethod run_initialization_callback_method (
195209 env, get_shared_realm_class (env), " runInitializationCallback" ,
196210 " (JLio/realm/internal/OsRealmConfig;Lio/realm/internal/SharedRealm$InitializationCallback;)V" , true );
197- JavaGlobalRef j_init_callback_ref (env, j_init_callback, true );
198- JavaGlobalRef j_config_ref (env, j_config, true );
199- config.initialization_function = [j_init_callback_ref, j_config_ref](SharedRealm realm) {
211+ // weak ref to avoid leaks caused by circular refs.
212+ JavaGlobalWeakRef j_init_cb_weak (env, j_init_callback);
213+ JavaGlobalWeakRef j_config_weak (env, j_config);
214+ config.initialization_function = [j_init_cb_weak, j_config_weak](SharedRealm realm) {
200215 JNIEnv* env = JniUtils::get_env (false );
201216 // Java needs a new pointer for the SharedRealm life control.
202217 SharedRealm* new_shared_realm_ptr = new SharedRealm (realm);
203- env->CallStaticVoidMethod (get_shared_realm_class (env), run_initialization_callback_method,
204- reinterpret_cast <jlong>(new_shared_realm_ptr), j_config_ref.get (),
205- j_init_callback_ref.get ());
218+ JavaGlobalRef config_global_ref = j_config_weak.global_ref (env);
219+ if (!config_global_ref) {
220+ return ;
221+ }
222+ j_init_cb_weak.call_with_local_ref (env, [&](JNIEnv* env, jobject obj) {
223+ env->CallStaticVoidMethod (get_shared_realm_class (env), run_initialization_callback_method,
224+ reinterpret_cast <jlong>(new_shared_realm_ptr), config_global_ref.get (),
225+ obj);
226+ });
206227 TERMINATE_JNI_IF_JAVA_EXCEPTION_OCCURRED (env);
207228 };
208229 }
0 commit comments