Force garbage collection of JavaScriptCore virtual machine on iOS
Asked Answered
H

1

7

Is there any way to force iOS (or Mac OS) JavaScriptCore VM garbage collector to run? I need it only to test for memory leaks, so private API would be fine.

Hyperon answered 28/2, 2016 at 23:13 Comment(0)
C
7

Use following function from JSBase.h:

/*!
@function JSGarbageCollect
@abstract Performs a JavaScript garbage collection.
@param ctx The execution context to use.
@discussion JavaScript values that are on the machine stack, in a register,
 protected by JSValueProtect, set as the global object of an execution context,
 or reachable from any such value will not be collected.

 During JavaScript execution, you are not required to call this function; the
 JavaScript engine will garbage collect as needed. JavaScript values created
 within a context group are automatically destroyed when the last reference
 to the context group is released.
*/
JS_EXPORT void JSGarbageCollect(JSContextRef ctx);

You can obtain JSContextRef from your JSContext, using JSGlobalContextRef readonly property.

Update

I've found next change in WebKit - bugs.webkit.org/show_bug.cgi?id=84476:

JSGarbageCollect should not synchronously call collectAllGarbage(). Instead, it should notify the GCActivityCallback that it has abandoned an object graph, which will set the timer to run at some point in the future that JSC can decide according to its own policies.

This explains why previous solution doesn't work as expected.

Digging deeper into WebKit sources, I found another interesting approach. Please, try following code:

JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef ctx);

@interface JSContext (GarbageCollection)

-(void)garbageCollect {
    JSSynchronousGarbageCollectForDebugging(self.JSGlobalContextRef);
}

@end

Simply call garbageCollect method on your JSContext instance after that. I've tried it locally on iOS and it seems to work.

Cultural answered 9/3, 2016 at 22:35 Comment(4)
Thanks Boris. Unfortunately, it looks like this doesn't actually trigger garbage collection - no difference if I call this method or not, garbage collector seems to be executed only when the used memory crosses a threshold.Hyperon
It works! (Actually, it's enough to just declare JSSynchronousGarbageCollectForDebugging and then run it from the code with ctx.JSGlobalContextRef .) Thanks!Hyperon
@silyevsk, glad to help :)Cultural
For anyone looking for this, but find that the symbol is still missing... extern "C" JSSynchronousGarbageCollectForDebugging(JSContextRef ctx); Either the JS_EXPORT macro has changed, or it depends where this code is used (I'm using it in c++ ios 14)Anceline

© 2022 - 2024 — McMap. All rights reserved.