https://bugs.webkit.org/show_bug.cgi?id=165533
<rdar://problem/
29318410>
Reviewed by Andreas Kling.
Have platformMemoryUsage return both resident and resident + swapped
values. This is now returned as a struct in a std::optional to better
support cases where values cannot or are not returned. Report these
values in logMemoryUsageChange.
Remove most of the ReliefLogger instances and their messages. We no
longer free up fastMalloc memory after each memory-release operation,
so there are no memory regions returned to the OS. Instead, we now
free up fastMalloc memory regions at the end of all memory-releasing
operations in one fell swoop and report a grand total of memory
returned.
No new tests -- no changes to user accessible functionality.
* page/MemoryRelease.cpp:
(WebCore::releaseNoncriticalMemory):
(WebCore::releaseCriticalMemory):
(WebCore::releaseMemory):
* page/cocoa/MemoryReleaseCocoa.mm:
(WebCore::platformReleaseMemory):
* platform/MemoryPressureHandler.cpp:
(WebCore::MemoryPressureHandler::releaseMemory):
(WebCore::MemoryPressureHandler::ReliefLogger::logMemoryUsageChange):
(WebCore::MemoryPressureHandler::ReliefLogger::platformMemoryUsage):
* platform/MemoryPressureHandler.h:
(WebCore::MemoryPressureHandler::ReliefLogger::ReliefLogger):
(WebCore::MemoryPressureHandler::ReliefLogger::~ReliefLogger):
(WebCore::MemoryPressureHandler::ReliefLogger::loggingEnabled):
* platform/cocoa/MemoryPressureHandlerCocoa.mm:
(WebCore::MemoryPressureHandler::platformReleaseMemory):
(WebCore::MemoryPressureHandler::ReliefLogger::platformMemoryUsage):
* platform/linux/MemoryPressureHandlerLinux.cpp:
* platform/win/MemoryPressureHandlerWin.cpp:
(WebCore::MemoryPressureHandler::ReliefLogger::platformMemoryUsage):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209744
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2016-12-12 Keith Rollin <krollin@apple.com>
+
+ Memory warning logging appears to capture resident footprint, missing compress/swap.
+ https://bugs.webkit.org/show_bug.cgi?id=165533
+ <rdar://problem/29318410>
+
+ Reviewed by Andreas Kling.
+
+ Have platformMemoryUsage return both resident and resident + swapped
+ values. This is now returned as a struct in a std::optional to better
+ support cases where values cannot or are not returned. Report these
+ values in logMemoryUsageChange.
+
+ Remove most of the ReliefLogger instances and their messages. We no
+ longer free up fastMalloc memory after each memory-release operation,
+ so there are no memory regions returned to the OS. Instead, we now
+ free up fastMalloc memory regions at the end of all memory-releasing
+ operations in one fell swoop and report a grand total of memory
+ returned.
+
+ No new tests -- no changes to user accessible functionality.
+
+ * page/MemoryRelease.cpp:
+ (WebCore::releaseNoncriticalMemory):
+ (WebCore::releaseCriticalMemory):
+ (WebCore::releaseMemory):
+ * page/cocoa/MemoryReleaseCocoa.mm:
+ (WebCore::platformReleaseMemory):
+ * platform/MemoryPressureHandler.cpp:
+ (WebCore::MemoryPressureHandler::releaseMemory):
+ (WebCore::MemoryPressureHandler::ReliefLogger::logMemoryUsageChange):
+ (WebCore::MemoryPressureHandler::ReliefLogger::platformMemoryUsage):
+ * platform/MemoryPressureHandler.h:
+ (WebCore::MemoryPressureHandler::ReliefLogger::ReliefLogger):
+ (WebCore::MemoryPressureHandler::ReliefLogger::~ReliefLogger):
+ (WebCore::MemoryPressureHandler::ReliefLogger::loggingEnabled):
+ * platform/cocoa/MemoryPressureHandlerCocoa.mm:
+ (WebCore::MemoryPressureHandler::platformReleaseMemory):
+ (WebCore::MemoryPressureHandler::ReliefLogger::platformMemoryUsage):
+ * platform/linux/MemoryPressureHandlerLinux.cpp:
+ * platform/win/MemoryPressureHandlerWin.cpp:
+ (WebCore::MemoryPressureHandler::ReliefLogger::platformMemoryUsage):
+
2016-12-12 Chris Dumez <cdumez@apple.com>
Document.visibilityState should use an IDL string enumeration
static void releaseNoncriticalMemory()
{
- {
- MemoryPressureHandler::ReliefLogger log("Purge inactive FontData");
- FontCache::singleton().purgeInactiveFontData();
- }
+ FontCache::singleton().purgeInactiveFontData();
- {
- MemoryPressureHandler::ReliefLogger log("Clear WidthCaches");
- clearWidthCaches();
- }
+ clearWidthCaches();
- {
- MemoryPressureHandler::ReliefLogger log("Discard Selector Query Cache");
- for (auto* document : Document::allDocuments())
- document->clearSelectorQueryCache();
- }
+ for (auto* document : Document::allDocuments())
+ document->clearSelectorQueryCache();
- {
- MemoryPressureHandler::ReliefLogger log("Prune MemoryCache dead resources");
- MemoryCache::singleton().pruneDeadResourcesToSize(0);
- }
+ MemoryCache::singleton().pruneDeadResourcesToSize(0);
- {
- MemoryPressureHandler::ReliefLogger log("Prune presentation attribute cache");
- StyledElement::clearPresentationAttributeCache();
- }
+ StyledElement::clearPresentationAttributeCache();
- {
- MemoryPressureHandler::ReliefLogger log("Clear inline stylesheet cache");
- InlineStyleSheetOwner::clearCache();
- }
+ InlineStyleSheetOwner::clearCache();
}
static void releaseCriticalMemory(Synchronous synchronous)
{
- {
- MemoryPressureHandler::ReliefLogger log("Empty the PageCache");
- // Right now, the only reason we call release critical memory while not under memory pressure is if the process is about to be suspended.
- PruningReason pruningReason = MemoryPressureHandler::singleton().isUnderMemoryPressure() ? PruningReason::MemoryPressure : PruningReason::ProcessSuspended;
- PageCache::singleton().pruneToSizeNow(0, pruningReason);
- }
+ // Right now, the only reason we call release critical memory while not under memory pressure is if the process is about to be suspended.
+ PruningReason pruningReason = MemoryPressureHandler::singleton().isUnderMemoryPressure() ? PruningReason::MemoryPressure : PruningReason::ProcessSuspended;
+ PageCache::singleton().pruneToSizeNow(0, pruningReason);
- {
- MemoryPressureHandler::ReliefLogger log("Prune MemoryCache live resources");
- MemoryCache::singleton().pruneLiveResourcesToSize(0, /*shouldDestroyDecodedDataForAllLiveResources*/ true);
- }
+ MemoryCache::singleton().pruneLiveResourcesToSize(0, /*shouldDestroyDecodedDataForAllLiveResources*/ true);
- {
- MemoryPressureHandler::ReliefLogger log("Drain CSSValuePool");
- CSSValuePool::singleton().drain();
- }
+ CSSValuePool::singleton().drain();
- {
- MemoryPressureHandler::ReliefLogger log("Discard StyleResolvers");
- Vector<RefPtr<Document>> documents;
- copyToVector(Document::allDocuments(), documents);
- for (auto& document : documents)
- document->styleScope().clearResolver();
- }
+ Vector<RefPtr<Document>> documents;
+ copyToVector(Document::allDocuments(), documents);
+ for (auto& document : documents)
+ document->styleScope().clearResolver();
- {
- MemoryPressureHandler::ReliefLogger log("Discard all JIT-compiled code");
- GCController::singleton().deleteAllCode(JSC::DeleteAllCodeIfNotCollecting);
- }
+ GCController::singleton().deleteAllCode(JSC::DeleteAllCodeIfNotCollecting);
#if ENABLE(VIDEO)
- {
- MemoryPressureHandler::ReliefLogger log("Dropping buffered data from paused media elements");
- for (auto* mediaElement : HTMLMediaElement::allMediaElements()) {
- if (mediaElement->paused())
- mediaElement->purgeBufferedDataIfPossible();
- }
+ for (auto* mediaElement : HTMLMediaElement::allMediaElements()) {
+ if (mediaElement->paused())
+ mediaElement->purgeBufferedDataIfPossible();
}
#endif
if (synchronous == Synchronous::Yes) {
- MemoryPressureHandler::ReliefLogger log("Collecting JavaScript garbage");
GCController::singleton().garbageCollectNow();
} else {
#if PLATFORM(IOS)
platformReleaseMemory(critical);
- {
- MemoryPressureHandler::ReliefLogger log("Release free FastMalloc memory");
- // FastMalloc has lock-free thread specific caches that can only be cleared from the thread itself.
- WorkerThread::releaseFastMallocFreeMemoryInAllThreads();
+ // FastMalloc has lock-free thread specific caches that can only be cleared from the thread itself.
+ WorkerThread::releaseFastMallocFreeMemoryInAllThreads();
#if ENABLE(ASYNC_SCROLLING) && !PLATFORM(IOS)
- ScrollingThread::dispatch([]() {
- WTF::releaseFastMallocFreeMemory();
- });
-#endif
+ ScrollingThread::dispatch([]() {
WTF::releaseFastMallocFreeMemory();
- }
+ });
+#endif
+ WTF::releaseFastMallocFreeMemory();
#if ENABLE(RESOURCE_USAGE)
Page::forEachPage([&](Page& page) {
void platformReleaseMemory(Critical)
{
- {
- MemoryPressureHandler::ReliefLogger log("Purging SQLite caches");
- _sqlite3_purgeEligiblePagerCacheMemory();
- }
+ _sqlite3_purgeEligiblePagerCacheMemory();
+
+ for (auto& pool : LayerPool::allLayerPools())
+ pool->drain();
- {
- MemoryPressureHandler::ReliefLogger log("Drain LayerPools");
- for (auto& pool : LayerPool::allLayerPools())
- pool->drain();
- }
#if USE(IOSURFACE)
- {
- MemoryPressureHandler::ReliefLogger log("Drain IOSurfacePool");
- IOSurfacePool::sharedPool().discardAllSurfaces();
- }
+ IOSurfacePool::sharedPool().discardAllSurfaces();
#endif
}
if (!m_lowMemoryHandler)
return;
+ ReliefLogger log("Total");
m_lowMemoryHandler(critical, synchronous);
platformReleaseMemory(critical);
}
#define MEMORYPRESSURE_LOG(...) WTFLogAlways(__VA_ARGS__)
#endif
- size_t currentMemory = platformMemoryUsage();
- if (currentMemory == static_cast<size_t>(-1) || m_initialMemory == static_cast<size_t>(-1)) {
+ auto currentMemory = platformMemoryUsage();
+ if (!currentMemory || !m_initialMemory) {
MEMORYPRESSURE_LOG("Memory pressure relief: " STRING_SPECIFICATION ": (Unable to get dirty memory information for process)", m_logString);
return;
}
- long memoryDiff = currentMemory - m_initialMemory;
- if (memoryDiff < 0)
- MEMORYPRESSURE_LOG("Memory pressure relief: " STRING_SPECIFICATION ": -dirty %ld bytes (from %zu to %zu)", m_logString, (memoryDiff * -1), m_initialMemory, currentMemory);
- else if (memoryDiff > 0)
- MEMORYPRESSURE_LOG("Memory pressure relief: " STRING_SPECIFICATION ": +dirty %ld bytes (from %zu to %zu)", m_logString, memoryDiff, m_initialMemory, currentMemory);
- else
- MEMORYPRESSURE_LOG("Memory pressure relief: " STRING_SPECIFICATION ": =dirty (at %zu bytes)", m_logString, currentMemory);
+ long residentDiff = currentMemory->resident - m_initialMemory->resident;
+ long physicalDiff = currentMemory->physical - m_initialMemory->physical;
+
+ MEMORYPRESSURE_LOG("Memory pressure relief: " STRING_SPECIFICATION ": res = %zu/%zu/%ld, res+swap = %zu/%zu/%ld",
+ m_logString,
+ m_initialMemory->resident, currentMemory->resident, residentDiff,
+ m_initialMemory->physical, currentMemory->physical, physicalDiff);
}
#if !PLATFORM(COCOA) && !OS(LINUX) && !PLATFORM(WIN)
void MemoryPressureHandler::holdOff(unsigned) { }
void MemoryPressureHandler::respondToMemoryPressure(Critical, Synchronous) { }
void MemoryPressureHandler::platformReleaseMemory(Critical) { }
-size_t MemoryPressureHandler::ReliefLogger::platformMemoryUsage() { return 0; }
+std::optional<MemoryPressureHandler::ReliefLogger::MemoryUsage> MemoryPressureHandler::ReliefLogger::platformMemoryUsage() { return std::nullopt; }
#endif
} // namespace WebCore
#include <wtf/FastMalloc.h>
#include <wtf/Forward.h>
#include <wtf/NeverDestroyed.h>
+#include <wtf/Optional.h>
#if PLATFORM(IOS)
#include <wtf/Lock.h>
public:
explicit ReliefLogger(const char *log)
: m_logString(log)
-#if !RELEASE_LOG_DISABLED
- , m_initialMemory(platformMemoryUsage())
-#else
- , m_initialMemory(s_loggingEnabled ? platformMemoryUsage() : 0)
-#endif
+ , m_initialMemory(loggingEnabled() ? platformMemoryUsage() : MemoryUsage { })
{
}
~ReliefLogger()
{
-#if !RELEASE_LOG_DISABLED
- logMemoryUsageChange();
-#else
- if (s_loggingEnabled)
+ if (loggingEnabled())
logMemoryUsageChange();
-#endif
}
+
const char* logString() const { return m_logString; }
static void setLoggingEnabled(bool enabled) { s_loggingEnabled = enabled; }
- static bool loggingEnabled() { return s_loggingEnabled; }
+ static bool loggingEnabled()
+ {
+#if RELEASE_LOG_DISABLED
+ return s_loggingEnabled;
+#else
+ return true;
+#endif
+ }
private:
- size_t platformMemoryUsage();
+ struct MemoryUsage {
+ size_t resident { 0 };
+ size_t physical { 0 };
+ };
+ std::optional<MemoryUsage> platformMemoryUsage();
void logMemoryUsageChange();
const char* m_logString;
- size_t m_initialMemory;
+ std::optional<MemoryUsage> m_initialMemory;
WEBCORE_EXPORT static bool s_loggingEnabled;
};
if (critical == Critical::Yes && (!isUnderMemoryPressure() || m_isSimulatingMemoryPressure)) {
// libcache listens to OS memory notifications, but for process suspension
// or memory pressure simulation, we need to prod it manually:
- ReliefLogger log("Purging libcache caches");
cache_simulate_memory_warning_event(DISPATCH_MEMORYPRESSURE_CRITICAL);
}
}
#endif
}
-size_t MemoryPressureHandler::ReliefLogger::platformMemoryUsage()
+std::optional<MemoryPressureHandler::ReliefLogger::MemoryUsage> MemoryPressureHandler::ReliefLogger::platformMemoryUsage()
{
task_vm_info_data_t vmInfo;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t err = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
if (err != KERN_SUCCESS)
- return static_cast<size_t>(-1);
+ return std::nullopt;
- return static_cast<size_t>(vmInfo.internal);
+ return MemoryUsage {static_cast<size_t>(vmInfo.internal), static_cast<size_t>(vmInfo.phys_footprint)};
}
#if PLATFORM(IOS)
void MemoryPressureHandler::platformReleaseMemory(Critical)
{
#ifdef __GLIBC__
- ReliefLogger log("Run malloc_trim");
malloc_trim(0);
#endif
}
-size_t MemoryPressureHandler::ReliefLogger::platformMemoryUsage()
+std::optional<MemoryPressureHandler::ReliefLogger::MemoryUsage> MemoryPressureHandler::ReliefLogger::platformMemoryUsage()
{
- return processMemoryUsage();
+ return MemoryUsage {processMemoryUsage(), 0};
}
void MemoryPressureHandler::setMemoryPressureMonitorHandle(int fd)
releaseMemory(critical, synchronous);
}
-size_t MemoryPressureHandler::ReliefLogger::platformMemoryUsage()
+std::optional<MemoryPressureHandler::ReliefLogger::MemoryUsage> MemoryPressureHandler::ReliefLogger::platformMemoryUsage()
{
- return 0;
+ return std::nullopt;
}
} // namespace WebCore