RenderTheme does not need to be per-page
[WebKit-https.git] / Source / WebCore / page / MemoryRelease.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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "MemoryRelease.h"
28
29 #include "CSSValuePool.h"
30 #include "Chrome.h"
31 #include "ChromeClient.h"
32 #include "CommonVM.h"
33 #include "Document.h"
34 #include "FontCache.h"
35 #include "GCController.h"
36 #include "HTMLMediaElement.h"
37 #include "InlineStyleSheetOwner.h"
38 #include "InspectorInstrumentation.h"
39 #include "Logging.h"
40 #include "MainFrame.h"
41 #include "MemoryCache.h"
42 #include "Page.h"
43 #include "PageCache.h"
44 #include "RenderTheme.h"
45 #include "ScrollingThread.h"
46 #include "StyleScope.h"
47 #include "StyledElement.h"
48 #include "WorkerThread.h"
49 #include <wtf/FastMalloc.h>
50 #include <wtf/SystemTracing.h>
51
52 #if PLATFORM(COCOA)
53 #include "ResourceUsageThread.h"
54 #endif
55
56 namespace WebCore {
57
58 static void releaseNoncriticalMemory()
59 {
60     RenderTheme::singleton().purgeCaches();
61
62     FontCache::singleton().purgeInactiveFontData();
63
64     clearWidthCaches();
65
66     for (auto* document : Document::allDocuments())
67         document->clearSelectorQueryCache();
68
69     MemoryCache::singleton().pruneDeadResourcesToSize(0);
70
71     InlineStyleSheetOwner::clearCache();
72 }
73
74 static void releaseCriticalMemory(Synchronous synchronous)
75 {
76     // Right now, the only reason we call release critical memory while not under memory pressure is if the process is about to be suspended.
77     PruningReason pruningReason = MemoryPressureHandler::singleton().isUnderMemoryPressure() ? PruningReason::MemoryPressure : PruningReason::ProcessSuspended;
78     PageCache::singleton().pruneToSizeNow(0, pruningReason);
79
80     MemoryCache::singleton().pruneLiveResourcesToSize(0, /*shouldDestroyDecodedDataForAllLiveResources*/ true);
81
82     CSSValuePool::singleton().drain();
83
84     Vector<RefPtr<Document>> documents;
85     copyToVector(Document::allDocuments(), documents);
86     for (auto& document : documents)
87         document->styleScope().clearResolver();
88
89     GCController::singleton().deleteAllCode(JSC::DeleteAllCodeIfNotCollecting);
90
91 #if ENABLE(VIDEO)
92     for (auto* mediaElement : HTMLMediaElement::allMediaElements()) {
93         if (mediaElement->paused())
94             mediaElement->purgeBufferedDataIfPossible();
95     }
96 #endif
97
98     if (synchronous == Synchronous::Yes) {
99         GCController::singleton().garbageCollectNow();
100     } else {
101 #if PLATFORM(IOS)
102         GCController::singleton().garbageCollectNowIfNotDoneRecently();
103 #else
104         GCController::singleton().garbageCollectSoon();
105 #endif
106     }
107 }
108
109 void releaseMemory(Critical critical, Synchronous synchronous)
110 {
111     TraceScope scope(MemoryPressureHandlerStart, MemoryPressureHandlerEnd, static_cast<uint64_t>(critical), static_cast<uint64_t>(synchronous));
112
113     if (critical == Critical::Yes) {
114         // Return unused pages back to the OS now as this will likely give us a little memory to work with.
115         WTF::releaseFastMallocFreeMemory();
116         releaseCriticalMemory(synchronous);
117     }
118
119     releaseNoncriticalMemory();
120
121     platformReleaseMemory(critical);
122
123     if (synchronous == Synchronous::Yes) {
124         // FastMalloc has lock-free thread specific caches that can only be cleared from the thread itself.
125         WorkerThread::releaseFastMallocFreeMemoryInAllThreads();
126 #if ENABLE(ASYNC_SCROLLING) && !PLATFORM(IOS)
127         ScrollingThread::dispatch([]() {
128             WTF::releaseFastMallocFreeMemory();
129         });
130 #endif
131         WTF::releaseFastMallocFreeMemory();
132     }
133
134 #if ENABLE(RESOURCE_USAGE)
135     Page::forEachPage([&](Page& page) {
136         InspectorInstrumentation::didHandleMemoryPressure(page, critical);
137     });
138 #endif
139 }
140
141 #if !RELEASE_LOG_DISABLED
142 static unsigned pageCount()
143 {
144     unsigned count = 0;
145     Page::forEachPage([&] (Page& page) {
146         if (!page.isUtilityPage())
147             ++count;
148     });
149     return count;
150 }
151 #endif
152
153 void logMemoryStatisticsAtTimeOfDeath()
154 {
155 #if !RELEASE_LOG_DISABLED
156 #if PLATFORM(COCOA)
157     auto pageSize = vmPageSize();
158     auto pages = pagesPerVMTag();
159
160     RELEASE_LOG(MemoryPressure, "Dirty memory per VM tag at time of death:");
161     for (unsigned i = 0; i < 256; ++i) {
162         size_t dirty = pages[i].dirty * pageSize;
163         if (!dirty)
164             continue;
165         String tagName = displayNameForVMTag(i);
166         if (!tagName)
167             tagName = String::format("Tag %u", i);
168         RELEASE_LOG(MemoryPressure, "%16s: %lu MB", tagName.latin1().data(), dirty / MB);
169     }
170 #endif
171
172     auto& vm = commonVM();
173     RELEASE_LOG(MemoryPressure, "Memory usage statistics at time of death:");
174     RELEASE_LOG(MemoryPressure, "GC heap size: %zu", vm.heap.size());
175     RELEASE_LOG(MemoryPressure, "GC heap extra memory size: %zu", vm.heap.extraMemorySize());
176 #if ENABLE(RESOURCE_USAGE)
177     RELEASE_LOG(MemoryPressure, "GC heap external memory: %zu", vm.heap.externalMemorySize());
178 #endif
179     RELEASE_LOG(MemoryPressure, "Global object count: %zu", vm.heap.globalObjectCount());
180
181     RELEASE_LOG(MemoryPressure, "Page count: %u", pageCount());
182     RELEASE_LOG(MemoryPressure, "Document count: %u", Document::allDocuments().size());
183     RELEASE_LOG(MemoryPressure, "Live JavaScript objects:");
184     for (auto& it : *vm.heap.objectTypeCounts())
185         RELEASE_LOG(MemoryPressure, "  %s: %d", it.key, it.value);
186 #endif
187 }
188
189 #if !PLATFORM(COCOA)
190 void platformReleaseMemory(Critical) { }
191 void jettisonExpensiveObjectsOnTopLevelNavigation() { }
192 void registerMemoryReleaseNotifyCallbacks() { }
193 #endif
194
195 } // namespace WebCore