Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (211570 => 211571)
--- trunk/Source/_javascript_Core/ChangeLog 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-02-02 18:35:55 UTC (rev 211571)
@@ -1,3 +1,20 @@
+2017-02-02 Andreas Kling <akl...@apple.com>
+
+ [Mac] In-process memory pressure monitor for WebContent processes.
+ <https://webkit.org/b/167491>
+ <rdar://problem/30116072>
+
+ Reviewed by Antti Koivisto.
+
+ Remove the sloppy "max live heap size" mechanism from JSC in favor of the new
+ WebCore-side memory footprint monitor.
+
+ * heap/Heap.cpp:
+ (JSC::Heap::updateAllocationLimits):
+ (JSC::Heap::didExceedMaxLiveSize): Deleted.
+ * heap/Heap.h:
+ (JSC::Heap::setMaxLiveSize): Deleted.
+
2017-02-02 Joseph Pecoraro <pecor...@apple.com>
Removed unused m_errorHandlingModeReentry from Interpreter
Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (211570 => 211571)
--- trunk/Source/_javascript_Core/heap/Heap.cpp 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp 2017-02-02 18:35:55 UTC (rev 211571)
@@ -1726,11 +1726,6 @@
m_sweeper->startSweeping();
}
-NEVER_INLINE void Heap::didExceedMaxLiveSize()
-{
- CRASH();
-}
-
void Heap::updateAllocationLimits()
{
static const bool verbose = false;
@@ -1762,9 +1757,6 @@
if (verbose)
dataLog("extraMemorySize() = ", extraMemorySize(), ", currentHeapSize = ", currentHeapSize, "\n");
-
- if (m_maxLiveSize && currentHeapSize > m_maxLiveSize)
- didExceedMaxLiveSize();
if (Options::gcMaxHeapSize() && currentHeapSize > Options::gcMaxHeapSize())
HeapStatistics::exitWithFailure();
Modified: trunk/Source/_javascript_Core/heap/Heap.h (211570 => 211571)
--- trunk/Source/_javascript_Core/heap/Heap.h 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/_javascript_Core/heap/Heap.h 2017-02-02 18:35:55 UTC (rev 211571)
@@ -132,9 +132,6 @@
VM* vm() const;
- // Set a hard limit where JSC will crash if live heap size exceeds it.
- void setMaxLiveSize(size_t size) { m_maxLiveSize = size; }
-
MarkedSpace& objectSpace() { return m_objectSpace; }
MachineThreads& machineThreads() { return m_machineThreads; }
@@ -603,9 +600,6 @@
size_t m_blockBytesAllocated { 0 };
size_t m_externalMemorySize { 0 };
#endif
-
- NO_RETURN_DUE_TO_CRASH void didExceedMaxLiveSize();
- size_t m_maxLiveSize { 0 };
std::unique_ptr<MutatorScheduler> m_scheduler;
Modified: trunk/Source/WTF/ChangeLog (211570 => 211571)
--- trunk/Source/WTF/ChangeLog 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WTF/ChangeLog 2017-02-02 18:35:55 UTC (rev 211571)
@@ -1,3 +1,19 @@
+2017-02-02 Andreas Kling <akl...@apple.com>
+
+ [Mac] In-process memory pressure monitor for WebContent processes.
+ <https://webkit.org/b/167491>
+ <rdar://problem/30116072>
+
+ Reviewed by Antti Koivisto.
+
+ Add a WTF helper function for getting the current process's memory footprint.
+
+ * WTF.xcodeproj/project.pbxproj:
+ * wtf/CMakeLists.txt:
+ * wtf/MemoryFootprint.cpp:
+ (WTF::memoryFootprint):
+ * wtf/MemoryFootprint.h:
+
2017-02-01 Wenson Hsieh <wenson_hs...@apple.com>
Unreviewed, fix the WebKit nightly open source build
Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (211570 => 211571)
--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2017-02-02 18:35:55 UTC (rev 211571)
@@ -337,6 +337,8 @@
A8A47487151A825B004123FF /* WTFThreadData.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4737B151A825B004123FF /* WTFThreadData.h */; };
A8A4748C151A8264004123FF /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4748B151A8264004123FF /* config.h */; };
AD7C434B1DD2A4A70026888B /* Expected.h in Headers */ = {isa = PBXBuildFile; fileRef = AD7C434A1DD2A4A70026888B /* Expected.h */; };
+ ADF2CE661E39F106006889DB /* MemoryFootprint.h in Headers */ = {isa = PBXBuildFile; fileRef = ADF2CE641E39F106006889DB /* MemoryFootprint.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ ADF2CE671E39F106006889DB /* MemoryFootprint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADF2CE651E39F106006889DB /* MemoryFootprint.cpp */; };
B38FD7BD168953E80065C969 /* FeatureDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = B38FD7BC168953E80065C969 /* FeatureDefines.h */; };
C4F8A93719C65EB400B2B15D /* Stopwatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C4F8A93619C65EB400B2B15D /* Stopwatch.h */; };
C8B0E1A1E01A486EB95E0D11 /* IndexSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 3137E1D7DBD84AC38FAE4D34 /* IndexSet.h */; };
@@ -719,6 +721,8 @@
A8A4737B151A825B004123FF /* WTFThreadData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTFThreadData.h; sourceTree = "<group>"; };
A8A4748B151A8264004123FF /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
AD7C434A1DD2A4A70026888B /* Expected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Expected.h; sourceTree = "<group>"; };
+ ADF2CE641E39F106006889DB /* MemoryFootprint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryFootprint.h; sourceTree = "<group>"; };
+ ADF2CE651E39F106006889DB /* MemoryFootprint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryFootprint.cpp; sourceTree = "<group>"; };
B38FD7BC168953E80065C969 /* FeatureDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FeatureDefines.h; sourceTree = "<group>"; };
C4F8A93619C65EB400B2B15D /* Stopwatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stopwatch.h; sourceTree = "<group>"; };
CD5497AA15857D0300B5BC30 /* MediaTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaTime.cpp; sourceTree = "<group>"; };
@@ -1005,6 +1009,8 @@
A8A472CB151A825B004123FF /* MD5.h */,
CD5497AA15857D0300B5BC30 /* MediaTime.cpp */,
CD5497AB15857D0300B5BC30 /* MediaTime.h */,
+ ADF2CE641E39F106006889DB /* MemoryFootprint.h */,
+ ADF2CE651E39F106006889DB /* MemoryFootprint.cpp */,
A8A472CC151A825B004123FF /* MessageQueue.h */,
A8A472CD151A825B004123FF /* MetaAllocator.cpp */,
A8A472CE151A825B004123FF /* MetaAllocator.h */,
@@ -1494,6 +1500,7 @@
A8A4741C151A825B004123FF /* RefPtr.h in Headers */,
A8A4741E151A825B004123FF /* RetainPtr.h in Headers */,
2CDED0F418115C85004DBA70 /* RunLoop.h in Headers */,
+ ADF2CE661E39F106006889DB /* MemoryFootprint.h in Headers */,
1469419216EAAF6D0024E146 /* RunLoopTimer.h in Headers */,
A5098B001C169E0700087797 /* SandboxSPI.h in Headers */,
14F3B0F715E45E4600210069 /* SaturatedArithmetic.h in Headers */,
@@ -1701,6 +1708,7 @@
1ACADD841884480100D8B71D /* DeprecatedSymbolsUsedBySafari.mm in Sources */,
A8A473AE151A825B004123FF /* diy-fp.cc in Sources */,
A8A473B0151A825B004123FF /* double-conversion.cc in Sources */,
+ ADF2CE671E39F106006889DB /* MemoryFootprint.cpp in Sources */,
A8A473BA151A825B004123FF /* dtoa.cpp in Sources */,
A8A473B3151A825B004123FF /* fast-dtoa.cc in Sources */,
0F7C5FB61D885CF20044F5E2 /* FastBitVector.cpp in Sources */,
Modified: trunk/Source/WTF/wtf/CMakeLists.txt (211570 => 211571)
--- trunk/Source/WTF/wtf/CMakeLists.txt 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WTF/wtf/CMakeLists.txt 2017-02-02 18:35:55 UTC (rev 211571)
@@ -64,6 +64,7 @@
MallocPtr.h
MathExtras.h
MediaTime.h
+ MemoryFootprint.h
MessageQueue.h
MetaAllocator.h
MetaAllocatorHandle.h
@@ -204,6 +205,7 @@
MD5.cpp
MainThread.cpp
MediaTime.cpp
+ MemoryFootprint.cpp
MetaAllocator.cpp
MonotonicTime.cpp
NumberOfCores.cpp
Copied: trunk/Source/WTF/wtf/MemoryFootprint.cpp (from rev 211570, trunk/Source/WebCore/bindings/js/CommonVM.cpp) (0 => 211571)
--- trunk/Source/WTF/wtf/MemoryFootprint.cpp (rev 0)
+++ trunk/Source/WTF/wtf/MemoryFootprint.cpp 2017-02-02 18:35:55 UTC (rev 211571)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MemoryFootprint.h"
+
+#if PLATFORM(COCOA)
+#include <mach/mach.h>
+#include <mach/task_info.h>
+#endif
+
+namespace WTF {
+
+std::optional<size_t> memoryFootprint()
+{
+#if PLATFORM(COCOA)
+ task_vm_info_data_t vmInfo;
+ mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
+ kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
+ if (result != KERN_SUCCESS)
+ return std::nullopt;
+ return static_cast<size_t>(vmInfo.phys_footprint);
+#else
+ return std::nullopt;
+#endif
+}
+
+}
Copied: trunk/Source/WTF/wtf/MemoryFootprint.h (from rev 211570, trunk/Source/WebCore/page/MemoryRelease.h) (0 => 211571)
--- trunk/Source/WTF/wtf/MemoryFootprint.h (rev 0)
+++ trunk/Source/WTF/wtf/MemoryFootprint.h 2017-02-02 18:35:55 UTC (rev 211571)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Optional.h>
+
+namespace WTF {
+
+WTF_EXPORT_PRIVATE std::optional<size_t> memoryFootprint();
+
+}
+
+using WTF::memoryFootprint;
+
Modified: trunk/Source/WebCore/ChangeLog (211570 => 211571)
--- trunk/Source/WebCore/ChangeLog 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/ChangeLog 2017-02-02 18:35:55 UTC (rev 211571)
@@ -1,3 +1,68 @@
+2017-02-02 Andreas Kling <akl...@apple.com>
+
+ [Mac] In-process memory pressure monitor for WebContent processes AKA websam
+ <https://webkit.org/b/167491>
+ <rdar://problem/30116072>
+
+ Reviewed by Antti Koivisto.
+
+ Add a new timer-based memory pressure monitor that checks the process memory
+ footprint every 30 seconds and reacts to changes by setting a MemoryUsagePolicy.
+
+ There are four MemoryUsagePolicy values:
+
+ - Unrestricted (below 1GB)
+ - Conservative (above 1GB)
+ - Strict (above 2GB)
+ - Panic (above 4GB, or 3GB if 32-bit)
+
+ For Strict and above, the old-style "isUnderMemoryPressure()" API will return true.
+
+ Transitioning to a higher policy will cause memory pressure handlers to run:
+
+ At Strict, we run the "non-critical" memory pressure handler, then carry on.
+
+ At Panic, we run the "critical" memory pressure handler. If that fails to recover
+ enough memory to bring us back below 4GB, we may kill the process:
+
+ A process is eligible to get killed for using too much memory if:
+
+ - It's not visible on screen (i.e it's a background tab.)
+ - It's not playing audio.
+ - It has not performed a main frame navigation in the last hour.
+
+ Before killing the process, an exit-time callback will run. This patch installs such
+ a callback that prints out some time-of-death statistics about C++ and _javascript_ memory
+ usage to hopefully help understand what was soaking up all the memory.
+
+ * bindings/js/CommonVM.cpp:
+ (WebCore::commonVMSlow):
+ * loader/FrameLoader.cpp:
+ (WebCore::FrameLoader::setState):
+ * page/MainFrame.cpp:
+ (WebCore::MainFrame::didCompleteLoad):
+ * page/MainFrame.h:
+ * page/MemoryRelease.cpp:
+ (WebCore::pageCount):
+ (WebCore::logMemoryStatisticsAtTimeOfDeath):
+ (WebCore::didExceedMemoryLimitAndFailedToRecover):
+ (WebCore::processIsEligibleForMemoryKill):
+ * page/MemoryRelease.h:
+ * page/ResourceUsageThread.h:
+ * page/cocoa/ResourceUsageThreadCocoa.mm:
+ (WebCore::vmPageSize):
+ * platform/MemoryPressureHandler.cpp:
+ (WebCore::MemoryPressureHandler::MemoryPressureHandler):
+ (WebCore::MemoryPressureHandler::setShouldUsePeriodicMemoryMonitor):
+ (WebCore::toString):
+ (WebCore::thresholdForPolicy):
+ (WebCore::policyForFootprint):
+ (WebCore::MemoryPressureHandler::measurementTimerFired):
+ * platform/MemoryPressureHandler.h:
+ (WebCore::MemoryPressureHandler::setMemoryKillCallback):
+ (WebCore::MemoryPressureHandler::setProcessIsEligibleForMemoryKillCallback):
+ (WebCore::MemoryPressureHandler::isUnderMemoryPressure):
+
2017-02-02 Chris Dumez <cdu...@apple.com>
[Crash] com.apple.WebKit.WebContent at WebKit: WebKit::WebPage::fromCorePage()
Modified: trunk/Source/WebCore/bindings/js/CommonVM.cpp (211570 => 211571)
--- trunk/Source/WebCore/bindings/js/CommonVM.cpp 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/bindings/js/CommonVM.cpp 2017-02-02 18:35:55 UTC (rev 211571)
@@ -46,10 +46,6 @@
ScriptController::initializeThreading();
g_commonVMOrNull = &VM::createLeaked(LargeHeap).leakRef();
-#if CPU(X86_64) || CPU(ARM64)
- static const size_t maxGCHeapSize = 4 * GB;
- g_commonVMOrNull->heap.setMaxLiveSize(maxGCHeapSize);
-#endif
g_commonVMOrNull->heap.acquireAccess(); // At any time, we may do things that affect the GC.
#if !PLATFORM(IOS)
g_commonVMOrNull->setExclusiveThread(std::this_thread::get_id());
Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (211570 => 211571)
--- trunk/Source/WebCore/loader/FrameLoader.cpp 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp 2017-02-02 18:35:55 UTC (rev 211571)
@@ -1742,7 +1742,7 @@
if (m_documentLoader)
m_documentLoader->stopRecordingResponses();
if (m_frame.isMainFrame() && oldState != newState)
- static_cast<MainFrame&>(m_frame).performanceLogging().didReachPointOfInterest(PerformanceLogging::MainFrameLoadCompleted);
+ static_cast<MainFrame&>(m_frame).didCompleteLoad();
}
}
Modified: trunk/Source/WebCore/page/MainFrame.cpp (211570 => 211571)
--- trunk/Source/WebCore/page/MainFrame.cpp 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/page/MainFrame.cpp 2017-02-02 18:35:55 UTC (rev 211571)
@@ -95,6 +95,12 @@
tree().removeChild(*child);
}
+void MainFrame::didCompleteLoad()
+{
+ m_timeOfLastCompletedLoad = MonotonicTime::now();
+ performanceLogging().didReachPointOfInterest(PerformanceLogging::MainFrameLoadCompleted);
+}
+
#if PLATFORM(MAC)
ScrollLatchingState* MainFrame::latchingState()
{
Modified: trunk/Source/WebCore/page/MainFrame.h (211570 => 211571)
--- trunk/Source/WebCore/page/MainFrame.h 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/page/MainFrame.h 2017-02-02 18:35:55 UTC (rev 211571)
@@ -69,6 +69,9 @@
PerformanceLogging& performanceLogging() const { return *m_performanceLogging; }
+ void didCompleteLoad();
+ MonotonicTime timeOfLastCompletedLoad() const { return m_timeOfLastCompletedLoad; }
+
private:
MainFrame(Page&, PageConfiguration&);
@@ -91,6 +94,8 @@
#endif
std::unique_ptr<PerformanceLogging> m_performanceLogging;
+
+ MonotonicTime m_timeOfLastCompletedLoad;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/page/MemoryRelease.cpp (211570 => 211571)
--- trunk/Source/WebCore/page/MemoryRelease.cpp 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/page/MemoryRelease.cpp 2017-02-02 18:35:55 UTC (rev 211571)
@@ -29,6 +29,7 @@
#include "CSSValuePool.h"
#include "Chrome.h"
#include "ChromeClient.h"
+#include "CommonVM.h"
#include "Document.h"
#include "FontCache.h"
#include "GCController.h"
@@ -35,6 +36,8 @@
#include "HTMLMediaElement.h"
#include "InlineStyleSheetOwner.h"
#include "InspectorInstrumentation.h"
+#include "Logging.h"
+#include "MainFrame.h"
#include "MemoryCache.h"
#include "Page.h"
#include "PageCache.h"
@@ -45,6 +48,10 @@
#include "WorkerThread.h"
#include <wtf/FastMalloc.h>
+#if PLATFORM(COCOA)
+#include "ResourceUsageThread.h"
+#endif
+
namespace WebCore {
static void releaseNoncriticalMemory()
@@ -128,6 +135,88 @@
#endif
}
+#if !RELEASE_LOG_DISABLED
+static unsigned pageCount()
+{
+ unsigned count = 0;
+ Page::forEachPage([&] (Page& page) {
+ if (!page.isUtilityPage())
+ ++count;
+ });
+ return count;
+}
+#endif
+
+void logMemoryStatisticsAtTimeOfDeath()
+{
+#if !RELEASE_LOG_DISABLED
+#if PLATFORM(COCOA)
+ auto pageSize = vmPageSize();
+ auto pages = pagesPerVMTag();
+
+ RELEASE_LOG(MemoryPressure, "Dirty memory per VM tag at time of death:");
+ for (unsigned i = 0; i < 256; ++i) {
+ size_t dirty = pages[i].dirty * pageSize;
+ if (!dirty)
+ continue;
+ String tagName = displayNameForVMTag(i);
+ if (!tagName)
+ tagName = String::format("Tag %u", i);
+ RELEASE_LOG(MemoryPressure, "%16s: %lu MB", tagName.latin1().data(), dirty / MB);
+ }
+#endif
+
+ auto& vm = commonVM();
+ RELEASE_LOG(MemoryPressure, "Memory usage statistics at time of death:");
+ RELEASE_LOG(MemoryPressure, "GC heap size: %zu", vm.heap.size());
+ RELEASE_LOG(MemoryPressure, "GC heap extra memory size: %zu", vm.heap.extraMemorySize());
+#if ENABLE(RESOURCE_USAGE)
+ RELEASE_LOG(MemoryPressure, "GC heap external memory: %zu", vm.heap.externalMemorySize());
+#endif
+ RELEASE_LOG(MemoryPressure, "Global object count: %zu", vm.heap.globalObjectCount());
+
+ RELEASE_LOG(MemoryPressure, "Page count: %u", pageCount());
+ RELEASE_LOG(MemoryPressure, "Document count: %u", Document::allDocuments().size());
+ RELEASE_LOG(MemoryPressure, "Live _javascript_ objects:");
+ for (auto& it : *vm.heap.objectTypeCounts())
+ RELEASE_LOG(MemoryPressure, " %s: %d", it.key, it.value);
+#endif
+}
+
+void didExceedMemoryLimitAndFailedToRecover()
+{
+ RELEASE_LOG(MemoryPressure, "Crashing non-visible process due to excessive memory usage + inability to free up memory below panic threshold.");
+ logMemoryStatisticsAtTimeOfDeath();
+ CRASH();
+}
+
+bool processIsEligibleForMemoryKill()
+{
+ bool hasVisiblePages = false;
+ bool hasAudiblePages = false;
+ bool hasMainFrameNavigatedInTheLastHour = false;
+
+ auto now = MonotonicTime::now();
+ Page::forEachPage([&] (Page& page) {
+ if (page.isUtilityPage())
+ return;
+ if (page.isVisible())
+ hasVisiblePages = true;
+ if (page.activityState() & ActivityState::IsAudible)
+ hasAudiblePages = true;
+ if (auto timeOfLastCompletedLoad = page.mainFrame().timeOfLastCompletedLoad()) {
+ if (now - timeOfLastCompletedLoad <= Seconds::fromMinutes(60))
+ hasMainFrameNavigatedInTheLastHour = true;
+ }
+ });
+
+ bool eligible = !hasVisiblePages && !hasAudiblePages && !hasMainFrameNavigatedInTheLastHour;
+ if (!eligible)
+ RELEASE_LOG(MemoryPressure, "Process not eligible for panic memory kill. Reasons: hasVisiblePages=%u, hasAudiblePages=%u, hasMainFrameNavigatedInTheLastHour=%u", hasVisiblePages, hasAudiblePages, hasMainFrameNavigatedInTheLastHour);
+
+ return eligible;
+}
+
#if !PLATFORM(COCOA)
void platformReleaseMemory(Critical) { }
void jettisonExpensiveObjectsOnTopLevelNavigation() { }
Modified: trunk/Source/WebCore/page/MemoryRelease.h (211570 => 211571)
--- trunk/Source/WebCore/page/MemoryRelease.h 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/page/MemoryRelease.h 2017-02-02 18:35:55 UTC (rev 211571)
@@ -33,5 +33,8 @@
void platformReleaseMemory(Critical);
void jettisonExpensiveObjectsOnTopLevelNavigation();
WEBCORE_EXPORT void registerMemoryReleaseNotifyCallbacks();
+WEBCORE_EXPORT void logMemoryStatisticsAtTimeOfDeath();
+WEBCORE_EXPORT NO_RETURN_DUE_TO_CRASH void didExceedMemoryLimitAndFailedToRecover();
+WEBCORE_EXPORT bool processIsEligibleForMemoryKill();
} // namespace WebCore
Modified: trunk/Source/WebCore/page/ResourceUsageThread.h (211570 => 211571)
--- trunk/Source/WebCore/page/ResourceUsageThread.h 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/page/ResourceUsageThread.h 2017-02-02 18:35:55 UTC (rev 211571)
@@ -80,6 +80,7 @@
};
const char* displayNameForVMTag(unsigned);
+size_t vmPageSize();
std::array<TagInfo, 256> pagesPerVMTag();
void logFootprintComparison(const std::array<TagInfo, 256>&, const std::array<TagInfo, 256>&);
#endif
Modified: trunk/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm (211570 => 211571)
--- trunk/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm 2017-02-02 18:35:55 UTC (rev 211571)
@@ -37,7 +37,7 @@
namespace WebCore {
-static size_t vmPageSize()
+size_t vmPageSize()
{
#if PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000
return vm_kernel_page_size;
Modified: trunk/Source/WebCore/platform/MemoryPressureHandler.cpp (211570 => 211571)
--- trunk/Source/WebCore/platform/MemoryPressureHandler.cpp 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/platform/MemoryPressureHandler.cpp 2017-02-02 18:35:55 UTC (rev 211571)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2014 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
#include "MemoryPressureHandler.h"
#include "Logging.h"
+#include <wtf/MemoryFootprint.h>
namespace WebCore {
@@ -39,12 +40,123 @@
}
MemoryPressureHandler::MemoryPressureHandler()
+ : m_measurementTimer(RunLoop::main(), this, &MemoryPressureHandler::measurementTimerFired)
#if OS(LINUX)
- : m_holdOffTimer(RunLoop::main(), this, &MemoryPressureHandler::holdOffTimerFired)
+ , m_holdOffTimer(RunLoop::main(), this, &MemoryPressureHandler::holdOffTimerFired)
#endif
{
}
+void MemoryPressureHandler::setShouldUsePeriodicMemoryMonitor(bool use)
+{
+ if (use)
+ m_measurementTimer.startRepeating(30);
+ else
+ m_measurementTimer.stop();
+}
+
+#if !RELEASE_LOG_DISABLED
+static const char* toString(MemoryUsagePolicy policy)
+{
+ switch (policy) {
+ case MemoryUsagePolicy::Unrestricted: return "Unrestricted";
+ case MemoryUsagePolicy::Conservative: return "Conservative";
+ case MemoryUsagePolicy::Strict: return "Strict";
+ case MemoryUsagePolicy::Panic: return "Panic";
+ }
+}
+#endif
+
+static constexpr size_t thresholdForPolicy(MemoryUsagePolicy policy)
+{
+ switch (policy) {
+ case MemoryUsagePolicy::Conservative:
+ return 1 * GB;
+ case MemoryUsagePolicy::Strict:
+ return 2 * GB;
+ case MemoryUsagePolicy::Panic:
+#if CPU(X86_64) || CPU(ARM64)
+ return 4 * GB;
+#else
+ return 3 * GB;
+#endif
+ case MemoryUsagePolicy::Unrestricted:
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+static constexpr MemoryUsagePolicy policyForFootprint(size_t footprint)
+{
+ if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Panic))
+ return MemoryUsagePolicy::Panic;
+ if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Strict))
+ return MemoryUsagePolicy::Strict;
+ if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Conservative))
+ return MemoryUsagePolicy::Conservative;
+ return MemoryUsagePolicy::Unrestricted;
+}
+
+void MemoryPressureHandler::measurementTimerFired()
+{
+ auto footprint = memoryFootprint();
+ if (!footprint)
+ return;
+
+ RELEASE_LOG(MemoryPressure, "Current memory footprint: %lu MB", footprint.value() / MB);
+
+ auto newPolicy = policyForFootprint(footprint.value());
+ if (newPolicy == m_memoryUsagePolicy) {
+ if (m_memoryUsagePolicy != MemoryUsagePolicy::Panic)
+ return;
+ RELEASE_LOG(MemoryPressure, "Memory usage still above panic threshold");
+ } else
+ RELEASE_LOG(MemoryPressure, "Memory usage policy changed: %s -> %s", toString(m_memoryUsagePolicy), toString(newPolicy));
+
+ m_memoryUsagePolicy = newPolicy;
+
+ if (newPolicy == MemoryUsagePolicy::Unrestricted)
+ return;
+
+ if (newPolicy == MemoryUsagePolicy::Conservative) {
+ // FIXME: Implement this policy by choosing which caches should respect it, and hooking them up.
+ return;
+ }
+
+ if (newPolicy == MemoryUsagePolicy::Strict) {
+ RELEASE_LOG(MemoryPressure, "Attempting to reduce memory footprint by freeing less important objects.");
+ releaseMemory(Critical::No, Synchronous::No);
+ return;
+ }
+
+ RELEASE_ASSERT(newPolicy == MemoryUsagePolicy::Panic);
+
+ RELEASE_LOG(MemoryPressure, "Attempting to reduce memory footprint by freeing more important objects.");
+ if (m_processIsEligibleForMemoryKillCallback) {
+ if (!m_processIsEligibleForMemoryKillCallback()) {
+ releaseMemory(Critical::Yes, Synchronous::No);
+ return;
+ }
+ }
+
+ releaseMemory(Critical::Yes, Synchronous::Yes);
+
+ // Remeasure footprint to see how well the pressure handler did.
+ footprint = memoryFootprint();
+ RELEASE_ASSERT(footprint);
+
+ RELEASE_LOG(MemoryPressure, "New memory footprint: %lu MB", footprint.value() / MB);
+ if (footprint.value() < thresholdForPolicy(MemoryUsagePolicy::Panic)) {
+ m_memoryUsagePolicy = policyForFootprint(footprint.value());
+ RELEASE_LOG(MemoryPressure, "Pressure reduced below panic threshold. New memory usage policy: %s", toString(m_memoryUsagePolicy));
+ return;
+ }
+
+ if (m_memoryKillCallback)
+ m_memoryKillCallback();
+}
+
void MemoryPressureHandler::beginSimulatedMemoryPressure()
{
m_isSimulatingMemoryPressure = true;
Modified: trunk/Source/WebCore/platform/MemoryPressureHandler.h (211570 => 211571)
--- trunk/Source/WebCore/platform/MemoryPressureHandler.h 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebCore/platform/MemoryPressureHandler.h 2017-02-02 18:35:55 UTC (rev 211571)
@@ -34,16 +34,16 @@
#include <wtf/Forward.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/Optional.h>
+#include <wtf/RunLoop.h>
#if PLATFORM(IOS)
#include <wtf/Lock.h>
#include <wtf/ThreadingPrimitives.h>
-#elif OS(LINUX)
-#include <wtf/RunLoop.h>
+#endif
+
#if USE(GLIB)
#include <wtf/glib/GRefPtr.h>
#endif
-#endif
namespace WebCore {
@@ -55,6 +55,13 @@
};
#endif
+enum class MemoryUsagePolicy {
+ Unrestricted, // Allocate as much as you want
+ Conservative, // Maybe you don't cache every single thing
+ Strict, // Time to start pinching pennies for real
+ Panic, // OH GOD WE'RE SINKING, THROW EVERYTHING OVERBOARD
+};
+
enum class Critical { No, Yes };
enum class Synchronous { No, Yes };
@@ -68,12 +75,24 @@
WEBCORE_EXPORT void install();
+ WEBCORE_EXPORT void setShouldUsePeriodicMemoryMonitor(bool);
+
+ void setMemoryKillCallback(WTF::Function<void()> function) { m_memoryKillCallback = WTFMove(function); }
+ void setProcessIsEligibleForMemoryKillCallback(WTF::Function<bool()> function) { m_processIsEligibleForMemoryKillCallback = WTFMove(function); }
+
void setLowMemoryHandler(LowMemoryHandler&& handler)
{
m_lowMemoryHandler = WTFMove(handler);
}
- bool isUnderMemoryPressure() const { return m_underMemoryPressure || m_isSimulatingMemoryPressure; }
+ bool isUnderMemoryPressure() const
+ {
+ return m_underMemoryPressure
+#if PLATFORM(MAC)
+ || m_memoryUsagePolicy >= MemoryUsagePolicy::Strict
+#endif
+ || m_isSimulatingMemoryPressure;
+ }
void setUnderMemoryPressure(bool b) { m_underMemoryPressure = b; }
#if PLATFORM(IOS)
@@ -149,6 +168,9 @@
void respondToMemoryPressure(Critical, Synchronous = Synchronous::No);
void platformReleaseMemory(Critical);
+ NO_RETURN_DUE_TO_CRASH void didExceedMemoryLimitAndFailedToRecover();
+ void measurementTimerFired();
+
#if OS(LINUX)
class EventFDPoller {
WTF_MAKE_NONCOPYABLE(EventFDPoller); WTF_MAKE_FAST_ALLOCATED;
@@ -170,12 +192,16 @@
#endif
bool m_installed { false };
- time_t m_lastRespondTime { 0 };
LowMemoryHandler m_lowMemoryHandler;
std::atomic<bool> m_underMemoryPressure;
bool m_isSimulatingMemoryPressure { false };
+ RunLoop::Timer<MemoryPressureHandler> m_measurementTimer;
+ MemoryUsagePolicy m_memoryUsagePolicy { MemoryUsagePolicy::Unrestricted };
+ WTF::Function<void()> m_memoryKillCallback;
+ WTF::Function<bool()> m_processIsEligibleForMemoryKillCallback;
+
#if PLATFORM(IOS)
// FIXME: Can we share more of this with OpenSource?
uint32_t m_memoryPressureReason { MemoryPressureReasonNone };
Modified: trunk/Source/WebKit2/ChangeLog (211570 => 211571)
--- trunk/Source/WebKit2/ChangeLog 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebKit2/ChangeLog 2017-02-02 18:35:55 UTC (rev 211571)
@@ -1,3 +1,16 @@
+2017-02-02 Andreas Kling <akl...@apple.com>
+
+ [Mac] In-process memory pressure monitor for WebContent processes.
+ <https://webkit.org/b/167491>
+ <rdar://problem/30116072>
+
+ Reviewed by Antti Koivisto.
+
+ Enable the in-process memory monitor for WebContent processes on macOS 10.12+
+
+ * WebProcess/WebProcess.cpp:
+ (WebKit::WebProcess::initializeWebProcess):
+
2017-02-02 Chris Dumez <cdu...@apple.com>
[Crash] com.apple.WebKit.WebContent at WebKit: WebKit::WebPage::fromCorePage()
Modified: trunk/Source/WebKit2/WebProcess/WebProcess.cpp (211570 => 211571)
--- trunk/Source/WebKit2/WebProcess/WebProcess.cpp 2017-02-02 18:33:29 UTC (rev 211570)
+++ trunk/Source/WebKit2/WebProcess/WebProcess.cpp 2017-02-02 18:35:55 UTC (rev 211571)
@@ -261,6 +261,15 @@
memoryPressureHandler.setLowMemoryHandler([] (Critical critical, Synchronous synchronous) {
WebCore::releaseMemory(critical, synchronous);
});
+#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
+ memoryPressureHandler.setShouldUsePeriodicMemoryMonitor(true);
+ memoryPressureHandler.setMemoryKillCallback([] () {
+ WebCore::didExceedMemoryLimitAndFailedToRecover();
+ });
+ memoryPressureHandler.setProcessIsEligibleForMemoryKillCallback([] () {
+ return WebCore::processIsEligibleForMemoryKill();
+ });
+#endif
memoryPressureHandler.install();
}