[WK2] Prune more resources from the MemoryCache before process suspension
[WebKit-https.git] / Source / WebCore / platform / MemoryPressureHandler.cpp
1 /*
2  * Copyright (C) 2011, 2014 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "MemoryPressureHandler.h"
28
29 #include "CSSValuePool.h"
30 #include "Document.h"
31 #include "FontCache.h"
32 #include "FontCascade.h"
33 #include "GCController.h"
34 #include "JSDOMWindow.h"
35 #include "MemoryCache.h"
36 #include "Page.h"
37 #include "PageCache.h"
38 #include "ScrollingThread.h"
39 #include "WorkerThread.h"
40 #include <JavaScriptCore/IncrementalSweeper.h>
41 #include <wtf/CurrentTime.h>
42 #include <wtf/FastMalloc.h>
43 #include <wtf/StdLibExtras.h>
44
45 namespace WebCore {
46
47 WEBCORE_EXPORT bool MemoryPressureHandler::ReliefLogger::s_loggingEnabled = false;
48
49 MemoryPressureHandler& MemoryPressureHandler::singleton()
50 {
51     static NeverDestroyed<MemoryPressureHandler> memoryPressureHandler;
52     return memoryPressureHandler;
53 }
54
55 MemoryPressureHandler::MemoryPressureHandler() 
56     : m_installed(false)
57     , m_lastRespondTime(0)
58     , m_lowMemoryHandler([this] (Critical critical, Synchronous synchronous) { releaseMemory(critical, synchronous); })
59     , m_underMemoryPressure(false)
60 #if PLATFORM(IOS)
61     // FIXME: Can we share more of this with OpenSource?
62     , m_memoryPressureReason(MemoryPressureReasonNone)
63     , m_clearPressureOnMemoryRelease(true)
64     , m_releaseMemoryBlock(0)
65     , m_observer(0)
66 #elif OS(LINUX)
67     , m_eventFD(0)
68     , m_pressureLevelFD(0)
69     , m_threadID(0)
70     , m_holdOffTimer(*this, &MemoryPressureHandler::holdOffTimerFired)
71 #endif
72 {
73 }
74
75 void MemoryPressureHandler::releaseNoncriticalMemory()
76 {
77     {
78         ReliefLogger log("Purge inactive FontData");
79         FontCache::singleton().purgeInactiveFontData();
80     }
81
82     {
83         ReliefLogger log("Clear WidthCaches");
84         clearWidthCaches();
85     }
86
87     {
88         ReliefLogger log("Discard Selector Query Cache");
89         for (auto* document : Document::allDocuments())
90             document->clearSelectorQueryCache();
91     }
92
93     {
94         ReliefLogger log("Clearing JS string cache");
95         JSDOMWindow::commonVM().stringCache.clear();
96     }
97
98     {
99         ReliefLogger log("Prune MemoryCache dead resources");
100         MemoryCache::singleton().pruneDeadResourcesToSize(0);
101     }
102 }
103
104 void MemoryPressureHandler::releaseCriticalMemory(Synchronous synchronous)
105 {
106     {
107         ReliefLogger log("Empty the PageCache");
108         // Right now, the only reason we call release critical memory while not under memory pressure is if the process is about to be suspended.
109         PruningReason pruningReason = isUnderMemoryPressure() ? PruningReason::MemoryPressure : PruningReason::ProcessSuspended;
110         PageCache::singleton().pruneToSizeNow(0, pruningReason);
111     }
112
113     {
114         ReliefLogger log("Prune MemoryCache live resources");
115         MemoryCache::singleton().pruneLiveResourcesToSize(0);
116     }
117
118     {
119         ReliefLogger log("Drain CSSValuePool");
120         cssValuePool().drain();
121     }
122
123     {
124         ReliefLogger log("Discard StyleResolvers");
125         for (auto* document : Document::allDocuments())
126             document->clearStyleResolver();
127     }
128
129     {
130         ReliefLogger log("Discard all JIT-compiled code");
131         gcController().discardAllCompiledCode();
132     }
133
134     {
135         ReliefLogger log("Invalidate font cache");
136         FontCache::singleton().invalidate();
137     }
138
139     if (synchronous == Synchronous::Yes) {
140         ReliefLogger log("Collecting JavaScript garbage");
141         gcController().garbageCollectNow();
142     } else {
143         // FIXME: We should do a garbage sweep and prune dead resources from the MemoryCache
144         // after the garbage collection has completed to free up more memory.
145         gcController().garbageCollectSoon();
146
147         // Do a full sweep of collected objects. garbageCollectNow() already does this so we only
148         // need to do this if it isn't called.
149         {
150             ReliefLogger log("Full JavaScript garbage sweep");
151             JSC::JSLockHolder lock(JSDOMWindow::commonVM());
152             JSDOMWindow::commonVM().heap.sweeper()->fullSweep();
153         }
154     }
155 }
156
157 void MemoryPressureHandler::releaseMemory(Critical critical, Synchronous synchronous)
158 {
159     if (critical == Critical::Yes)
160         releaseCriticalMemory(synchronous);
161
162     releaseNoncriticalMemory();
163
164     platformReleaseMemory(critical);
165
166     {
167         ReliefLogger log("Release free FastMalloc memory");
168         // FastMalloc has lock-free thread specific caches that can only be cleared from the thread itself.
169         WorkerThread::releaseFastMallocFreeMemoryInAllThreads();
170 #if ENABLE(ASYNC_SCROLLING) && !PLATFORM(IOS)
171         ScrollingThread::dispatch(WTF::releaseFastMallocFreeMemory);
172 #endif
173         WTF::releaseFastMallocFreeMemory();
174     }
175 }
176
177 #if !PLATFORM(COCOA) && !OS(LINUX)
178 void MemoryPressureHandler::install() { }
179 void MemoryPressureHandler::uninstall() { }
180 void MemoryPressureHandler::holdOff(unsigned) { }
181 void MemoryPressureHandler::respondToMemoryPressure(Critical, Synchronous) { }
182 void MemoryPressureHandler::platformReleaseMemory(Critical) { }
183 void MemoryPressureHandler::ReliefLogger::platformLog() { }
184 size_t MemoryPressureHandler::ReliefLogger::platformMemoryUsage() { return 0; }
185 #endif
186
187 } // namespace WebCore