Many modern media control tests leak documents in testing
[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 "CSSFontSelector.h"
30 #include "CSSValuePool.h"
31 #include "CachedResourceLoader.h"
32 #include "Chrome.h"
33 #include "ChromeClient.h"
34 #include "CommonVM.h"
35 #include "Document.h"
36 #include "FontCache.h"
37 #include "Frame.h"
38 #include "GCController.h"
39 #include "HTMLMediaElement.h"
40 #include "InlineStyleSheetOwner.h"
41 #include "InspectorInstrumentation.h"
42 #include "Logging.h"
43 #include "MemoryCache.h"
44 #include "Page.h"
45 #include "PageCache.h"
46 #include "RenderTheme.h"
47 #include "ScrollingThread.h"
48 #include "StyleScope.h"
49 #include "StyledElement.h"
50 #include "TextPainter.h"
51 #include "WorkerThread.h"
52 #include <wtf/FastMalloc.h>
53 #include <wtf/SystemTracing.h>
54
55 #if PLATFORM(COCOA)
56 #include "ResourceUsageThread.h"
57 #endif
58
59 namespace WebCore {
60
61 static void releaseNoncriticalMemory()
62 {
63     RenderTheme::singleton().purgeCaches();
64
65     FontCache::singleton().purgeInactiveFontData();
66     FontDescription::invalidateCaches();
67
68     clearWidthCaches();
69     TextPainter::clearGlyphDisplayLists();
70
71     for (auto* document : Document::allDocuments())
72         document->clearSelectorQueryCache();
73
74     MemoryCache::singleton().pruneDeadResourcesToSize(0);
75
76     InlineStyleSheetOwner::clearCache();
77 }
78
79 static void releaseCriticalMemory(Synchronous synchronous)
80 {
81     // Right now, the only reason we call release critical memory while not under memory pressure is if the process is about to be suspended.
82     PruningReason pruningReason = MemoryPressureHandler::singleton().isUnderMemoryPressure() ? PruningReason::MemoryPressure : PruningReason::ProcessSuspended;
83     PageCache::singleton().pruneToSizeNow(0, pruningReason);
84
85     MemoryCache::singleton().pruneLiveResourcesToSize(0, /*shouldDestroyDecodedDataForAllLiveResources*/ true);
86
87     CSSValuePool::singleton().drain();
88
89     for (auto& document : copyToVectorOf<RefPtr<Document>>(Document::allDocuments())) {
90         document->styleScope().releaseMemory();
91         document->fontSelector().emptyCaches();
92         document->cachedResourceLoader().garbageCollectDocumentResources();
93     }
94
95     GCController::singleton().deleteAllCode(JSC::DeleteAllCodeIfNotCollecting);
96
97 #if ENABLE(VIDEO)
98     for (auto* mediaElement : HTMLMediaElement::allMediaElements()) {
99         if (mediaElement->paused())
100             mediaElement->purgeBufferedDataIfPossible();
101     }
102 #endif
103
104     if (synchronous == Synchronous::Yes) {
105         GCController::singleton().garbageCollectNow();
106     } else {
107 #if PLATFORM(IOS)
108         GCController::singleton().garbageCollectNowIfNotDoneRecently();
109 #else
110         GCController::singleton().garbageCollectSoon();
111 #endif
112     }
113 }
114
115 void releaseMemory(Critical critical, Synchronous synchronous)
116 {
117     TraceScope scope(MemoryPressureHandlerStart, MemoryPressureHandlerEnd, static_cast<uint64_t>(critical), static_cast<uint64_t>(synchronous));
118
119     if (critical == Critical::Yes) {
120         // Return unused pages back to the OS now as this will likely give us a little memory to work with.
121         WTF::releaseFastMallocFreeMemory();
122         releaseCriticalMemory(synchronous);
123     }
124
125     releaseNoncriticalMemory();
126
127     platformReleaseMemory(critical);
128
129     if (synchronous == Synchronous::Yes) {
130         // FastMalloc has lock-free thread specific caches that can only be cleared from the thread itself.
131         WorkerThread::releaseFastMallocFreeMemoryInAllThreads();
132 #if ENABLE(ASYNC_SCROLLING) && !PLATFORM(IOS)
133         ScrollingThread::dispatch(WTF::releaseFastMallocFreeMemory);
134 #endif
135         WTF::releaseFastMallocFreeMemory();
136     }
137
138 #if ENABLE(RESOURCE_USAGE)
139     Page::forEachPage([&](Page& page) {
140         InspectorInstrumentation::didHandleMemoryPressure(page, critical);
141     });
142 #endif
143 }
144
145 #if !RELEASE_LOG_DISABLED
146 static unsigned pageCount()
147 {
148     unsigned count = 0;
149     Page::forEachPage([&] (Page& page) {
150         if (!page.isUtilityPage())
151             ++count;
152     });
153     return count;
154 }
155 #endif
156
157 void logMemoryStatisticsAtTimeOfDeath()
158 {
159 #if !RELEASE_LOG_DISABLED
160 #if PLATFORM(COCOA)
161     auto pageSize = vmPageSize();
162     auto pages = pagesPerVMTag();
163
164     RELEASE_LOG(MemoryPressure, "Dirty memory per VM tag at time of death:");
165     for (unsigned i = 0; i < 256; ++i) {
166         size_t dirty = pages[i].dirty * pageSize;
167         if (!dirty)
168             continue;
169         String tagName = displayNameForVMTag(i);
170         if (!tagName)
171             tagName = String::format("Tag %u", i);
172         RELEASE_LOG(MemoryPressure, "%16s: %lu MB", tagName.latin1().data(), dirty / MB);
173     }
174 #endif
175
176     auto& vm = commonVM();
177     RELEASE_LOG(MemoryPressure, "Memory usage statistics at time of death:");
178     RELEASE_LOG(MemoryPressure, "GC heap size: %zu", vm.heap.size());
179     RELEASE_LOG(MemoryPressure, "GC heap extra memory size: %zu", vm.heap.extraMemorySize());
180 #if ENABLE(RESOURCE_USAGE)
181     RELEASE_LOG(MemoryPressure, "GC heap external memory: %zu", vm.heap.externalMemorySize());
182 #endif
183     RELEASE_LOG(MemoryPressure, "Global object count: %zu", vm.heap.globalObjectCount());
184
185     RELEASE_LOG(MemoryPressure, "Page count: %u", pageCount());
186     RELEASE_LOG(MemoryPressure, "Document count: %u", Document::allDocuments().size());
187     RELEASE_LOG(MemoryPressure, "Live JavaScript objects:");
188     for (auto& it : *vm.heap.objectTypeCounts())
189         RELEASE_LOG(MemoryPressure, "  %s: %d", it.key, it.value);
190 #endif
191 }
192
193 #if !PLATFORM(COCOA)
194 void platformReleaseMemory(Critical) { }
195 void jettisonExpensiveObjectsOnTopLevelNavigation() { }
196 void registerMemoryReleaseNotifyCallbacks() { }
197 #endif
198
199 } // namespace WebCore