[jsscripting] Fix memory leak that crashes openHAB (#13824)
* [jsscripting] Fix memory-leak caused by com.oracle.truffle.host.HostObject Fixes this memory leak by making the HostAccess for the GraalJSScriptEngine available in a static final variable instead of creating it for each new engine. Solution proposed in https://github.com/oracle/graaljs/issues/121#issuecomment-690179954. Sharing a single engine across all Contexts (as proposed in https://github.com/oracle/graaljs/issues/121#issuecomment-880056648) is not possible, because core expects a ScriptEngine. Signed-off-by: Florian Hotze <florianh_dev@icloud.com> * [jsscripting] Update JavaDoc Signed-off-by: Florian Hotze <florianh_dev@icloud.com> * [jsscripting] Close `GraalJSScriptEngine` when `OpenhabGraalJSScriptEngine` is closed My breakpoint inside the close method of GraalJSScriptEngine did not trigger until this change was made. Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
This commit is contained in:
parent
224d86e88a
commit
42b8505bef
@ -58,7 +58,7 @@ import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine;
|
|||||||
* @author Jonathan Gilbert - Initial contribution
|
* @author Jonathan Gilbert - Initial contribution
|
||||||
* @author Dan Cunningham - Script injections
|
* @author Dan Cunningham - Script injections
|
||||||
* @author Florian Hotze - Create lock object for multi-thread synchronization; Inject the {@link JSRuntimeFeatures}
|
* @author Florian Hotze - Create lock object for multi-thread synchronization; Inject the {@link JSRuntimeFeatures}
|
||||||
* into the JS context
|
* into the JS context; Fix memory leak caused by HostObject by making HostAccess reference static
|
||||||
*/
|
*/
|
||||||
public class OpenhabGraalJSScriptEngine
|
public class OpenhabGraalJSScriptEngine
|
||||||
extends InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable<GraalJSScriptEngine> {
|
extends InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable<GraalJSScriptEngine> {
|
||||||
@ -66,10 +66,24 @@ public class OpenhabGraalJSScriptEngine
|
|||||||
private static final Logger LOGGER = LoggerFactory.getLogger(OpenhabGraalJSScriptEngine.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(OpenhabGraalJSScriptEngine.class);
|
||||||
private static final String GLOBAL_REQUIRE = "require(\"@jsscripting-globals\");";
|
private static final String GLOBAL_REQUIRE = "require(\"@jsscripting-globals\");";
|
||||||
private static final String REQUIRE_WRAPPER_NAME = "__wraprequire__";
|
private static final String REQUIRE_WRAPPER_NAME = "__wraprequire__";
|
||||||
// final CommonJS search path for our library
|
/** Final CommonJS search path for our library */
|
||||||
private static final Path NODE_DIR = Paths.get("node_modules");
|
private static final Path NODE_DIR = Paths.get("node_modules");
|
||||||
|
/** Provides unlimited host access as well as custom translations from JS to Java Objects */
|
||||||
|
private static final HostAccess HOST_ACCESS = HostAccess.newBuilder(HostAccess.ALL)
|
||||||
|
// Translate JS-Joda ZonedDateTime to java.time.ZonedDateTime
|
||||||
|
.targetTypeMapping(Value.class, ZonedDateTime.class, (v) -> v.hasMember("withFixedOffsetZone"), v -> {
|
||||||
|
return ZonedDateTime.parse(v.invokeMember("withFixedOffsetZone").invokeMember("toString").asString());
|
||||||
|
}, HostAccess.TargetMappingPrecedence.LOW)
|
||||||
|
|
||||||
// shared lock object for synchronization of multi-thread access
|
// Translate JS-Joda Duration to java.time.Duration
|
||||||
|
.targetTypeMapping(Value.class, Duration.class,
|
||||||
|
// picking two members to check as Duration has many common function names
|
||||||
|
(v) -> v.hasMember("minusDuration") && v.hasMember("toNanos"), v -> {
|
||||||
|
return Duration.ofNanos(v.invokeMember("toNanos").asLong());
|
||||||
|
}, HostAccess.TargetMappingPrecedence.LOW)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
/** Shared lock object for synchronization of multi-thread access */
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
private final JSRuntimeFeatures jsRuntimeFeatures;
|
private final JSRuntimeFeatures jsRuntimeFeatures;
|
||||||
|
|
||||||
@ -91,27 +105,11 @@ public class OpenhabGraalJSScriptEngine
|
|||||||
|
|
||||||
LOGGER.debug("Initializing GraalJS script engine...");
|
LOGGER.debug("Initializing GraalJS script engine...");
|
||||||
|
|
||||||
// Custom translate JS Objects - > Java Objects
|
|
||||||
HostAccess hostAccess = HostAccess.newBuilder(HostAccess.ALL)
|
|
||||||
// Translate JS-Joda ZonedDateTime to java.time.ZonedDateTime
|
|
||||||
.targetTypeMapping(Value.class, ZonedDateTime.class, (v) -> v.hasMember("withFixedOffsetZone"), v -> {
|
|
||||||
return ZonedDateTime
|
|
||||||
.parse(v.invokeMember("withFixedOffsetZone").invokeMember("toString").asString());
|
|
||||||
}, HostAccess.TargetMappingPrecedence.LOW)
|
|
||||||
|
|
||||||
// Translate JS-Joda Duration to java.time.Duration
|
|
||||||
.targetTypeMapping(Value.class, Duration.class,
|
|
||||||
// picking two members to check as Duration has many common function names
|
|
||||||
(v) -> v.hasMember("minusDuration") && v.hasMember("toNanos"), v -> {
|
|
||||||
return Duration.ofNanos(v.invokeMember("toNanos").asLong());
|
|
||||||
}, HostAccess.TargetMappingPrecedence.LOW)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
delegate = GraalJSScriptEngine.create(
|
delegate = GraalJSScriptEngine.create(
|
||||||
Engine.newBuilder().allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false")
|
Engine.newBuilder().allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false")
|
||||||
.build(),
|
.build(),
|
||||||
Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true).allowHostAccess(hostAccess)
|
Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true)
|
||||||
.option("js.commonjs-require-cwd", JSDependencyTracker.LIB_PATH)
|
.allowHostAccess(HOST_ACCESS).option("js.commonjs-require-cwd", JSDependencyTracker.LIB_PATH)
|
||||||
.option("js.nashorn-compat", "true") // to ease migration
|
.option("js.nashorn-compat", "true") // to ease migration
|
||||||
.option("js.ecmascript-version", "2021") // nashorn compat will enforce es5 compatibility, we
|
.option("js.ecmascript-version", "2021") // nashorn compat will enforce es5 compatibility, we
|
||||||
// want ecma2021
|
// want ecma2021
|
||||||
@ -236,6 +234,7 @@ public class OpenhabGraalJSScriptEngine
|
|||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
jsRuntimeFeatures.close();
|
jsRuntimeFeatures.close();
|
||||||
|
delegate.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user