Skip to content

Commit

Permalink
Add call to collectGarbage for JSIExecutor::handleMemoryPressure
Browse files Browse the repository at this point in the history
Summary:
Someone pointed out in this Github issue: facebook#27532
that the memory pressure warning from Android was being ignored, when it can easily
be used to start a garbage collection on the JS runtime.

Changelog: [Internal] Add a memory pressure handler for jsi::Runtime

Reviewed By: mhorowitz

Differential Revision: D20072943

fbshipit-source-id: 869a14068aa02bd378e8b26d8c18b76a5d0f7bc0
  • Loading branch information
Riley Dulin authored and osdnk committed Mar 9, 2020
1 parent bb705f5 commit 276dce0
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 0 deletions.
69 changes: 69 additions & 0 deletions ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <folly/json.h>
#include <glog/logging.h>
#include <jsi/JSIDynamic.h>
#include <jsi/instrumentation.h>

#include <sstream>
#include <stdexcept>
Expand Down Expand Up @@ -273,6 +274,74 @@ bool JSIExecutor::isInspectable() {
return runtime_->isInspectable();
}

void JSIExecutor::handleMemoryPressure(int pressureLevel) {
// The level is an enum value passed by the Android OS to an onTrimMemory
// event callback. Defined in ComponentCallbacks2.
enum AndroidMemoryPressure {
TRIM_MEMORY_BACKGROUND = 40,
TRIM_MEMORY_COMPLETE = 80,
TRIM_MEMORY_MODERATE = 60,
TRIM_MEMORY_RUNNING_CRITICAL = 15,
TRIM_MEMORY_RUNNING_LOW = 10,
TRIM_MEMORY_RUNNING_MODERATE = 5,
TRIM_MEMORY_UI_HIDDEN = 20,
};
const char *levelName;
switch (pressureLevel) {
case TRIM_MEMORY_BACKGROUND:
levelName = "TRIM_MEMORY_BACKGROUND";
break;
case TRIM_MEMORY_COMPLETE:
levelName = "TRIM_MEMORY_COMPLETE";
break;
case TRIM_MEMORY_MODERATE:
levelName = "TRIM_MEMORY_MODERATE";
break;
case TRIM_MEMORY_RUNNING_CRITICAL:
levelName = "TRIM_MEMORY_RUNNING_CRITICAL";
break;
case TRIM_MEMORY_RUNNING_LOW:
levelName = "TRIM_MEMORY_RUNNING_LOW";
break;
case TRIM_MEMORY_RUNNING_MODERATE:
levelName = "TRIM_MEMORY_RUNNING_MODERATE";
break;
case TRIM_MEMORY_UI_HIDDEN:
levelName = "TRIM_MEMORY_UI_HIDDEN";
break;
default:
levelName = "UNKNOWN";
break;
}

switch (pressureLevel) {
case TRIM_MEMORY_RUNNING_LOW:
case TRIM_MEMORY_RUNNING_MODERATE:
case TRIM_MEMORY_UI_HIDDEN:
// For non-severe memory trims, do nothing.
LOG(INFO) << "Memory warning (pressure level: " << levelName
<< ") received by JS VM, ignoring because it's non-severe";
break;
case TRIM_MEMORY_BACKGROUND:
case TRIM_MEMORY_COMPLETE:
case TRIM_MEMORY_MODERATE:
case TRIM_MEMORY_RUNNING_CRITICAL:
// For now, pressureLevel is unused by collectGarbage.
// This may change in the future if the JS GC has different styles of
// collections.
LOG(INFO) << "Memory warning (pressure level: " << levelName
<< ") received by JS VM, running a GC";
runtime_->instrumentation().collectGarbage();
break;
default:
// Use the raw number instead of the name here since the name is
// meaningless.
LOG(WARNING) << "Memory warning (pressure level: " << pressureLevel
<< ") received by JS VM, unrecognized pressure level";
break;
}
}

void JSIExecutor::bindBridge() {
std::call_once(bindFlag_, [this] {
SystraceSection s("JSIExecutor::bindBridge (once)");
Expand Down
1 change: 1 addition & 0 deletions ReactCommon/jsiexecutor/jsireact/JSIExecutor.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class JSIExecutor : public JSExecutor {
std::string getDescription() override;
void *getJavaScriptContext() override;
bool isInspectable() override;
void handleMemoryPressure(int pressureLevel) override;

// An implementation of JSIScopedTimeoutInvoker that simply runs the
// invokee, with no timeout.
Expand Down

0 comments on commit 276dce0

Please sign in to comment.