From 1b17e3f4936e866a55bc905a8664309ded97d225 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Wed, 8 Nov 2017 15:28:03 +0200 Subject: [android] MapRendererRunnable - avoid weak reference table overflow Apparently on some devices the weak reference table is limited (numbers around 52000). Even though we don't use that many weak references, when GC is not called for a while they can stack up and a crash will occur before the GC has had the time to clear the references. The C++ peer now holds on to a global ref (strong) which can be obtained to queue the java peer and then release automatically so that the GC can take over after the runnable has been executed. --- platform/android/src/map_renderer.cpp | 10 +++++++--- platform/android/src/map_renderer_runnable.cpp | 10 ++++++---- platform/android/src/map_renderer_runnable.hpp | 7 +++---- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/platform/android/src/map_renderer.cpp b/platform/android/src/map_renderer.cpp index 7655455210..36e8142bfa 100644 --- a/platform/android/src/map_renderer.cpp +++ b/platform/android/src/map_renderer.cpp @@ -41,15 +41,19 @@ ActorRef MapRenderer::actor() const { } void MapRenderer::schedule(std::weak_ptr scheduled) { - // Create a runnable and schedule it on the gl thread + // Create a runnable android::UniqueEnv _env = android::AttachEnv(); auto runnable = std::make_unique(*_env, std::move(scheduled)); + // Obtain ownership of the peer (gets transferred to the MapRenderer on the JVM for later GC) + auto peer = runnable->peer(); + + // Queue the event on the Java Peer static auto queueEvent = javaClass.GetMethod)>(*_env, "queueEvent"); - javaPeer->Call(*_env, queueEvent, runnable->getPeer()); + javaPeer->Call(*_env, queueEvent, *peer); - // Release the object as it will be destroyed on GC of the Java Peer + // Release the c++ peer as it will be destroyed on GC of the Java Peer runnable.release(); } diff --git a/platform/android/src/map_renderer_runnable.cpp b/platform/android/src/map_renderer_runnable.cpp index df8cba5e55..4dc6611c40 100644 --- a/platform/android/src/map_renderer_runnable.cpp +++ b/platform/android/src/map_renderer_runnable.cpp @@ -8,11 +8,13 @@ namespace android { MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::weak_ptr mailbox_) : mailbox(std::move(mailbox_)) { - // Create the Java peer + // Create the Java peer and hold on to a global reference + // Not using a weak reference here as this might oerflow + // the weak reference table on some devices jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 5); static auto constructor = javaClass.GetConstructor(env); auto instance = javaClass.New(env, constructor, reinterpret_cast(this)); - javaPeer = SeizeGenericWeakRef(env, jni::Object(jni::NewWeakGlobalRef(env, instance.Get()).release())); + javaPeer = instance.NewGlobalRef(env); } MapRendererRunnable::~MapRendererRunnable() = default; @@ -21,8 +23,8 @@ void MapRendererRunnable::run(jni::JNIEnv&) { Mailbox::maybeReceive(mailbox); } -jni::Object MapRendererRunnable::getPeer() { - return *javaPeer; +jni::UniqueObject MapRendererRunnable::peer() { + return std::move(javaPeer); } // Static methods // diff --git a/platform/android/src/map_renderer_runnable.hpp b/platform/android/src/map_renderer_runnable.hpp index 75646a442d..46fb028d26 100644 --- a/platform/android/src/map_renderer_runnable.hpp +++ b/platform/android/src/map_renderer_runnable.hpp @@ -8,8 +8,6 @@ #include -#include "jni/generic_global_ref_deleter.hpp" - namespace mbgl { namespace android { @@ -39,10 +37,11 @@ public: void run(jni::JNIEnv&); - jni::Object getPeer(); + // Transfers ownership of the Peer object to the caller + jni::UniqueObject peer(); private: - GenericUniqueWeakObject javaPeer; + jni::UniqueObject javaPeer; std::weak_ptr mailbox; }; -- cgit v1.2.1