Merge branch 'java-director-leak'

* java-director-leak:
  Cosmetic tidyup in SWIG_JAVA_DETACH_ON_THREAD_END code
  Java: Move auxiliary methods into JObjectWrapper.
  Java: Option to detach from the JVM in the thread destructor.

Conflicts:
	CHANGES.current
This commit is contained in:
William S Fulton 2022-05-28 10:24:08 +01:00
commit 1d6f4b4eae
2 changed files with 42 additions and 1 deletions

View file

@ -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) Version 4.1.0 (in progress)
=========================== ===========================
2022-05-28: 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-27: xypron 2022-05-27: xypron
[Python] #2277 Define PY_SSIZE_T_CLEAN macro before #include "Python.h" as [Python] #2277 Define PY_SSIZE_T_CLEAN macro before #include "Python.h" as
recommended in Python 3.7 and later. recommended in Python 3.7 and later.

View file

@ -51,6 +51,10 @@ SWIGINTERN int Swig::GetThreadName(char *name, size_t len) {
#endif #endif
#if defined(SWIG_JAVA_DETACH_ON_THREAD_END)
#include <pthread.h>
#endif
namespace Swig { namespace Swig {
/* Java object wrapper */ /* Java object wrapper */
@ -133,6 +137,19 @@ namespace Swig {
} }
} }
#if defined(SWIG_JAVA_DETACH_ON_THREAD_END)
static void detach(void *jvm) {
static_cast<JavaVM *>(jvm)->DetachCurrentThread();
}
static void make_detach_key() {
pthread_key_create(&detach_key_, detach);
}
/* thread-local key to register a destructor */
static pthread_key_t detach_key_;
#endif
private: private:
/* pointer to Java object */ /* pointer to Java object */
jobject jthis_; jobject jthis_;
@ -140,6 +157,10 @@ namespace Swig {
bool weak_global_; bool weak_global_;
}; };
#if defined(SWIG_JAVA_DETACH_ON_THREAD_END)
pthread_key_t JObjectWrapper::detach_key_;
#endif
/* Local JNI reference deleter */ /* Local JNI reference deleter */
class LocalRefGuard { class LocalRefGuard {
JNIEnv *jenv_; JNIEnv *jenv_;
@ -201,9 +222,19 @@ namespace Swig {
#else #else
director_->swig_jvm_->AttachCurrentThread(jenv, &args); director_->swig_jvm_->AttachCurrentThread(jenv, &args);
#endif #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, JObjectWrapper::make_detach_key);
pthread_setspecific(JObjectWrapper::detach_key_, director->swig_jvm_);
#endif
} }
~JNIEnvWrapper() { ~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. // 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. // 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) if (env_status == JNI_EDETACHED)