Bug 145773 - Allow one sync GC per gcTimer interval on critical memory pressure warning
Summary: Allow one sync GC per gcTimer interval on critical memory pressure warning
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Chris Dumez
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-06-08 15:02 PDT by Chris Dumez
Modified: 2015-08-20 09:15 PDT (History)
5 users (show)

See Also:


Attachments
Patch (10.51 KB, patch)
2015-06-08 20:08 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (10.69 KB, patch)
2015-06-08 20:26 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (12.52 KB, patch)
2015-06-09 14:05 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Dumez 2015-06-08 15:02:46 PDT
On critical memory pressure warning, we currently call GCController::garbageCollectSoon(), which does not offer any guarantee on when the garbage collection will actually take place.
On critical memory pressure, we need to free up memory as soon as possible to avoid getting killed so this is an issue. Also, the fact that we clear the PageCache on critical memory pressure means a GC would likely be useful, even it is did not do much work the last time the gcTimer fired.

As a result, the proposal is to allow one synchronous GC per gcTimer interval on critical memory pressure warning. This makes us more responsive to critical memory pressure and avoids doing synchronous GCs too often.
Comment 1 Chris Dumez 2015-06-08 20:08:45 PDT
Created attachment 254539 [details]
Patch
Comment 2 Chris Dumez 2015-06-08 20:26:42 PDT
Created attachment 254541 [details]
Patch
Comment 3 Darin Adler 2015-06-09 11:28:41 PDT
Comment on attachment 254541 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=254541&action=review

> Source/JavaScriptCore/heap/Heap.cpp:1422
> +        collectAllGarbage();

What is the rationale for not setting m_didSyncGCRecently true here?
Comment 4 Chris Dumez 2015-06-09 11:41:32 PDT
Comment on attachment 254541 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=254541&action=review

>> Source/JavaScriptCore/heap/Heap.cpp:1422
>> +        collectAllGarbage();
> 
> What is the rationale for not setting m_didSyncGCRecently true here?

m_didSyncGCRecently is only reset to false when the m_fullActivityCallback timer fires so if this timer is disabled (m_fullActivityCallback is null) it will never be reset to false.
Geoff can correct me but I don't think this (m_fullActivityCallback being null) normally happens in practice though as I don't see any call sites to JSDisableGCTimer().
Comment 5 Geoffrey Garen 2015-06-09 13:13:06 PDT
r=me

Perhaps it would be nice to refactor this to be a feature of the timer, rather than a feature of the Heap object. That would help clarify the behavior in the case where there is not timer.
Comment 6 Chris Dumez 2015-06-09 14:05:47 PDT
Created attachment 254600 [details]
Patch
Comment 7 Chris Dumez 2015-06-09 14:06:16 PDT
(In reply to comment #5)
> r=me
> 
> Perhaps it would be nice to refactor this to be a feature of the timer,
> rather than a feature of the Heap object. That would help clarify the
> behavior in the case where there is not timer.

I reuploaded another iteration doing this. Please take another look.
Comment 8 Geoffrey Garen 2015-06-09 14:21:33 PDT
Comment on attachment 254600 [details]
Patch

r=me
Comment 9 Andreas Kling 2015-06-09 14:43:13 PDT
v.nice
Comment 10 WebKit Commit Bot 2015-06-09 15:16:09 PDT
Comment on attachment 254600 [details]
Patch

Clearing flags on attachment: 254600

Committed r185387: <http://trac.webkit.org/changeset/185387>
Comment 11 WebKit Commit Bot 2015-06-09 15:16:15 PDT
All reviewed patches have been landed.  Closing bug.
Comment 12 Joseph Pecoraro 2015-08-19 23:59:15 PDT
Comment on attachment 254600 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=254600&action=review

> Source/WebCore/bindings/js/GCController.cpp:101
> +#if USE(CF)
> +    JSLockHolder lock(JSDOMWindow::commonVM());
> +    if (!JSDOMWindow::commonVM().heap.isBusy())
> +        JSDOMWindow::commonVM().heap.collectAllGarbageIfNotDoneRecently();
> +#else
> +    garbageCollectSoon();
> +#endif

Why is this different for USE(CF) and not? Heap::collectAllGarbageIfNotDoneRecently appears to be available for all ports so it seems they could both have the same implementation, is there a reason I'm overlooking?
Comment 13 Chris Dumez 2015-08-20 09:15:14 PDT
Comment on attachment 254600 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=254600&action=review

>> Source/WebCore/bindings/js/GCController.cpp:101
>> +#endif
> 
> Why is this different for USE(CF) and not? Heap::collectAllGarbageIfNotDoneRecently appears to be available for all ports so it seems they could both have the same implementation, is there a reason I'm overlooking?

Maybe Heap::collectAllGarbageIfNotDoneRecently() should be behind USE(CF) then.

What we do in Heap::collectAllGarbageIfNotDoneRecently():
if (wasGCdRecenty)
  garbageCollectSoon();
else
  garbageCollectNow();

Note that in Heap::collectAllGarbageIfNotDoneRecently(), we call reportAbandonedObjectGraph() to do the garbageCollectSoon(). However, if you look at the implementation of GCController::garbageCollectSoon(), it looks like:
    // We only use reportAbandonedObjectGraph on systems with CoreFoundation 
    // since it uses a run-loop-based timer that is currently only available on
    // systems with CoreFoundation. If and when the notion of a run loop is pushed 
    // down into WTF so that more platforms can take advantage of it, we will be 
    // able to use reportAbandonedObjectGraph on more platforms.
#if USE(CF)
    JSLockHolder lock(JSDOMWindow::commonVM());
    JSDOMWindow::commonVM().heap.reportAbandonedObjectGraph();
#else
    garbageCollectOnNextRunLoop();
#endif

So to make Heap::collectAllGarbageIfNotDoneRecently() work for !USE(CF), it looks like we would need to use a Timer instead of calling simply reportAbandonedObjectGraph().