diff --git a/CHANGES.current b/CHANGES.current index 4a3bd7d98..9d804f53b 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,16 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-05-23: jkuebart + [Java] On some versions of Android, specifically Android 6, + detaching the current thread from the JVM after every invocation + causes a memory leak. + + Offer SWIG_JAVA_DETACH_ON_THREAD_END to configure a behaviour + where the JVM is only detached in the thread destructor. + + See https://developer.android.com/training/articles/perf-jni#threads. + 2022-05-15: erezgeva, eiselekd [Lua, Perl, Octave, PHP, Tcl] #2275 #2276 #2283 Add argcargv.i library containing (int ARGC, char **ARGV) multi-argument typemaps. diff --git a/Lib/java/director.swg b/Lib/java/director.swg index e911a3da7..f7c4f2d8a 100644 --- a/Lib/java/director.swg +++ b/Lib/java/director.swg @@ -51,6 +51,22 @@ SWIGINTERN int Swig::GetThreadName(char *name, size_t len) { #endif +#if defined(SWIG_JAVA_DETACH_ON_THREAD_END) +#include +namespace { + + void detach(void* jvm) { + static_cast(jvm)->DetachCurrentThread(); + } + + pthread_key_t detachKey; + void makeDetachKey() { + pthread_key_create(&detachKey, detach); + } + +} +#endif + namespace Swig { /* Java object wrapper */ @@ -201,9 +217,19 @@ namespace Swig { #else director_->swig_jvm_->AttachCurrentThread(jenv, &args); #endif + +#if defined(SWIG_JAVA_DETACH_ON_THREAD_END) + // At least on Android 6, detaching after every call causes a memory leak. + // Instead, register a thread desructor and detach only when the thread ends. + // See https://developer.android.com/training/articles/perf-jni#threads + static pthread_once_t once = PTHREAD_ONCE_INIT; + + pthread_once(&once, makeDetachKey); + pthread_setspecific(detachKey, director->swig_jvm_); +#endif } ~JNIEnvWrapper() { -#if !defined(SWIG_JAVA_NO_DETACH_CURRENT_THREAD) +#if !defined(SWIG_JAVA_DETACH_ON_THREAD_END) && !defined(SWIG_JAVA_NO_DETACH_CURRENT_THREAD) // Some JVMs, eg jdk-1.4.2 and lower on Solaris have a bug and crash with the DetachCurrentThread call. // However, without this call, the JVM hangs on exit when the thread was not created by the JVM and creates a memory leak. if (env_status == JNI_EDETACHED)