WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
NEW
184015
API::SharedJSContext caches its JSContext for at most one second
https://bugs.webkit.org/show_bug.cgi?id=184015
Summary
API::SharedJSContext caches its JSContext for at most one second
ide
Reported
2018-03-26 11:07:08 PDT
The -[WKWebView evaluateJavaScript:completionHandler:] API and any other APIs that internally use API::SerializedScriptValue (see APISerializedScriptValueCocoa.mm) use a JSContext to convert a JSValueRef to an Objective-C Foundation object. Creating the JSContext on an iPhone X with iOS 11.2 takes about 12~16ms and is significant relative to the other work API::SerializedScriptValue does. The SharedJSContext class caches a JSContext to mitigate this overhead. However, the cache has a TTL of one second. This means that if one second elapses between calls to -[WKWebView evaluateJavaScript:completionHandler:], the previously cached JSContext is discarded and we pay the cost of creating a new one as well as a new JSVirtualMachine. You can observe this by timing sequential calls to -[WKWebView evaluateJavaScript:completionHandler:] -- they are generally under 1ms except for once a second when there is an extra 12~16ms. If SharedJSContext were to cache its JSContext indefinitely (e.g., until a memory pressure event) or to cache the underlying JSVirtualMachine, it seems likely that the latency of WKWebView's calls would decrease and become more consistent, and noticeably improve the responsiveness of apps that make these calls in response to UI events.
Attachments
Add attachment
proposed patch, testcase, etc.
Alexey Proskuryakov
Comment 1
2018-03-27 14:23:08 PDT
The code is in WebKit/UIProcess/API/Cocoa/APISerializedScriptValueCocoa.mm. Seems like the lifetime should be extended by each use?
Radar WebKit Bug Importer
Comment 2
2018-03-27 14:23:27 PDT
<
rdar://problem/38927316
>
ide
Comment 3
2018-03-27 14:30:17 PDT
It would also be desirable for JS evaluation to be responsive if the app has been idle for a while. For example, if UITouch events invoke -[WKWebView evaluateJavaScript:completionHandler:] and wait for a result via the completionHandler before updating the screen, using a cached JSContext could save a frame or two, assuming 60 FPS. So, it'd be useful to keep the JSContext around for a longer period of time until an event like memory pressure or backgrounding the app occurs.
Ryosuke Niwa
Comment 4
2018-04-03 19:00:54 PDT
It's a bit strange that we have a random eviction policy of one second. It makes more sense to keep it alive as long as WKWebView is alive until there is some kind of memory pressure. Keith / Saam, is there a reason SharedJSContext "expires" after one second?
Saam Barati
Comment 5
2018-08-15 15:50:29 PDT
(In reply to Ryosuke Niwa from
comment #4
)
> It's a bit strange that we have a random eviction policy of one second. It > makes more sense to keep it alive as long as WKWebView is alive until there > is some kind of memory pressure. > > Keith / Saam, is there a reason SharedJSContext "expires" after one second?
I don't know of any reason. Geoff, do you know?
Geoffrey Garen
Comment 6
2018-08-16 11:48:28 PDT
> > Keith / Saam, is there a reason SharedJSContext "expires" after one second? > > I don't know of any reason. > > Geoff, do you know?
It looks like I asked for some limit on this cache in
bug 146416
. Given that a JS VM retains a bunch of memory, I think it's an important goal that a WKWebView client should be able to allocate a WebView, do some work with it, and then throw it away without retaining a JS VM forever. Here are some solutions that I think would be reasonable: (1) Make allocation of a JSContext faster than 16ms. (Jeepers!) (2) Change API::SerializedScriptValue::deserialize to accept a WKWebView argument, and keep a weak reference to that argument, and clear its cache when the set of all WebViews that has ever called API::SerializedScriptValue::deserialize becomes empty. I think we should probably do both of these.
Geoffrey Garen
Comment 7
2018-08-16 11:52:10 PDT
...I think it's also OK to increase the timer to something like 10s or 30s -- but it's not clear that would fully solve the performance complaint here. I don't agree with the suggestion to rely on a memory pressure event. Caches that only evict upon memory pressure create a tragedy of the commons where memory pressure events become more common, and then you just always evict all of your caches all of the time. It is preferable, when possible, to evict eagerly when you know you don't need your cache anymore.
Keith Miller
Comment 8
2018-08-16 11:57:11 PDT
(In reply to Geoffrey Garen from
comment #7
)
> ...I think it's also OK to increase the timer to something like 10s or 30s > -- but it's not clear that would fully solve the performance complaint here. > > I don't agree with the suggestion to rely on a memory pressure event. Caches > that only evict upon memory pressure create a tragedy of the commons where > memory pressure events become more common, and then you just always evict > all of your caches all of the time. It is preferable, when possible, to > evict eagerly when you know you don't need your cache anymore.
We could also evict the cache on after some number of full GCs where it's unused.
Geoffrey Garen
Comment 9
2018-08-16 12:40:18 PDT
> We could also evict the cache on after some number of full GCs where it's > unused.
I don't think there's any mechanism that will cause an idle VM to do full GCs.
Saam Barati
Comment 10
2018-08-17 01:21:51 PDT
(In reply to Geoffrey Garen from
comment #6
)
> > > Keith / Saam, is there a reason SharedJSContext "expires" after one second? > > > > I don't know of any reason. > > > > Geoff, do you know? > > It looks like I asked for some limit on this cache in
bug 146416
. Given that > a JS VM retains a bunch of memory, I think it's an important goal that a > WKWebView client should be able to allocate a WebView, do some work with it, > and then throw it away without retaining a JS VM forever. > > Here are some solutions that I think would be reasonable: > > (1) Make allocation of a JSContext faster than 16ms. (Jeepers!)
I like this idea.
> > (2) Change API::SerializedScriptValue::deserialize to accept a WKWebView > argument, and keep a weak reference to that argument, and clear its cache > when the set of all WebViews that has ever called > API::SerializedScriptValue::deserialize becomes empty. > > I think we should probably do both of these.
Keith Miller
Comment 11
2018-08-18 03:16:41 PDT
(In reply to Geoffrey Garen from
comment #9
)
> > We could also evict the cache on after some number of full GCs where it's > > unused. > > I don't think there's any mechanism that will cause an idle VM to do full > GCs.
I thought we have a GC timer that occasionally fires?
Geoffrey Garen
Comment 12
2018-08-20 15:47:10 PDT
> > > We could also evict the cache on after some number of full GCs where it's > > > unused. > > > > I don't think there's any mechanism that will cause an idle VM to do full > > GCs. > > I thought we have a GC timer that occasionally fires?
We have a GC timer. It fires in response to activity. After a VM goes idle, you can expect the GC timer to fire one last time, but you can't expect it to fire a "number" of times -- unless that number is zero or one :P.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug