Bug 805855 - Free dirty pages in response to all memory-pressure messages. r=jlebar

This commit is contained in:
Gabriele Svelto 2012-11-12 17:41:23 +01:00
parent 1e1d781bc1
commit ffd5580b48
5 changed files with 120 additions and 19 deletions

View File

@ -587,3 +587,7 @@ pref("general.useragent.override.facebook.com", "\(Mobile#(Android; Mobile");
pref("general.useragent.override.youtube.com", "\(Mobile#(Android; Mobile");
pref("jsloader.reuseGlobal", true);
// Enable freeing dirty pages when minimizing memory; this reduces memory
// consumption when applications are sent to the background.
pref("memory.free_dirty_pages", true);

View File

@ -3810,6 +3810,9 @@ pref("memory.low_memory_notification_interval_ms", 10000);
// window to be collected via the GC/CC.
pref("memory.ghost_window_timeout_seconds", 60);
// Disable freeing dirty pages when minimizing memory.
pref("memory.free_dirty_pages", false);
pref("social.enabled", false);
// Disable idle observer fuzz, because only privileged content can access idle

View File

@ -5,22 +5,37 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/AvailableMemoryTracker.h"
#include "nsThread.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#include "mozilla/Preferences.h"
#include "nsWindowsDllInterceptor.h"
#include "prinrval.h"
#include "pratom.h"
#include "prenv.h"
#include "nsIMemoryReporter.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIRunnable.h"
#include "nsISupports.h"
#include "nsPrintfCString.h"
#include <windows.h>
#include "nsThread.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#if defined(XP_WIN)
# include "nsWindowsDllInterceptor.h"
# include <windows.h>
#endif
#if defined(MOZ_MEMORY)
# include "jemalloc.h"
#endif // MOZ_MEMORY
using namespace mozilla;
namespace {
#if defined(XP_WIN)
// We don't want our diagnostic functions to call malloc, because that could
// call VirtualAlloc, and we'd end up back in here! So here are a few simple
// debugging macros (modeled on jemalloc's), which hopefully won't allocate.
@ -461,6 +476,86 @@ public:
NS_IMPL_ISUPPORTS1(NumLowPhysicalMemoryEventsMemoryReporter, nsIMemoryReporter)
#endif // defined(XP_WIN)
/**
* This runnable is executed in response to a memory-pressure event; we spin
* the event-loop when receiving the memory-pressure event in the hope that
* other observers will synchronously free some memory that we'll be able to
* purge here.
*/
class nsJemallocFreeDirtyPagesRunnable MOZ_FINAL : public nsIRunnable
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
};
NS_IMPL_ISUPPORTS1(nsJemallocFreeDirtyPagesRunnable, nsIRunnable)
NS_IMETHODIMP
nsJemallocFreeDirtyPagesRunnable::Run()
{
MOZ_ASSERT(NS_IsMainThread());
#if defined(MOZ_JEMALLOC)
mallctl("arenas.purge", nullptr, 0, nullptr, 0);
#elif defined(MOZ_MEMORY)
jemalloc_free_dirty_pages();
#endif
return NS_OK;
}
/**
* The memory pressure watcher is used for listening to memory-pressure events
* and reacting upon them. We use one instance per process currently only for
* cleaning up dirty unused pages held by jemalloc.
*/
class nsMemoryPressureWatcher MOZ_FINAL : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
void Init();
};
NS_IMPL_ISUPPORTS1(nsMemoryPressureWatcher, nsIObserver)
/**
* Initialize and subscribe to the memory-pressure events. We subscribe to the
* observer service in this method and not in the constructor because we need
* to hold a strong reference to 'this' before calling the observer service.
*/
void
nsMemoryPressureWatcher::Init()
{
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->AddObserver(this, "memory-pressure", /* ownsWeak */ false);
}
}
/**
* Reacts to all types of memory-pressure events, launches a runnable to
* free dirty pages held by jemalloc.
* @see nsMemoryPressureWatcher::FreeDirtyPages
*/
NS_IMETHODIMP
nsMemoryPressureWatcher::Observe(nsISupports *subject, const char *topic,
const PRUnichar *data)
{
MOZ_ASSERT(!strcmp(topic, "memory-pressure"), "Unknown topic");
nsRefPtr<nsIRunnable> runnable = new nsJemallocFreeDirtyPagesRunnable();
NS_DispatchToMainThread(runnable);
return NS_OK;
}
} // anonymous namespace
namespace mozilla {
@ -468,7 +563,7 @@ namespace AvailableMemoryTracker {
void Activate()
{
#if defined(_M_IX86)
#if defined(_M_IX86) && defined(XP_WIN)
MOZ_ASSERT(sInitialized);
MOZ_ASSERT(!sHooksActive);
@ -496,6 +591,12 @@ void Activate()
}
sHooksActive = true;
#endif
if (Preferences::GetBool("memory.free_dirty_pages", false)) {
// This object is held alive by the observer service.
nsRefPtr<nsMemoryPressureWatcher> watcher = new nsMemoryPressureWatcher();
watcher->Init();
}
}
void Init()
@ -509,7 +610,7 @@ void Init()
// process, because we aren't going to run out of virtual memory, and the
// system is likely to have a fair bit of physical memory.
#if defined(_M_IX86)
#if defined(_M_IX86) && defined(XP_WIN)
// Don't register the hooks if we're a build instrumented for PGO: If we're
// an instrumented build, the compiler adds function calls all over the place
// which may call VirtualAlloc; this makes it hard to prevent

View File

@ -10,10 +10,9 @@
namespace mozilla {
namespace AvailableMemoryTracker {
// The AvailableMemoryTracker is implemented only on Windows. But to make
// callers' lives easier, we stub out empty calls for all its public functions.
// So you can always initialize the AvailableMemoryTracker; it just might not
// do anything.
// The AvailableMemoryTracker launches a memory pressure watcher on all
// platforms to react to low-memory situations and on Windows it implements
// the full functionality used to monitor how much memory is available.
//
// Init() must be called before any other threads have started, because it
// modifies the in-memory implementations of some DLL functions in
@ -22,13 +21,8 @@ namespace AvailableMemoryTracker {
// The hooks don't do anything until Activate() is called. It's an error to
// call Activate() without first calling Init().
#if defined(XP_WIN)
void Init();
void Activate();
#else
void Init() {}
void Activate() {}
#endif
} // namespace AvailableMemoryTracker
} // namespace mozilla

View File

@ -43,6 +43,7 @@ CPPSRCS = \
nsGZFileWriter.cpp \
nsMemoryInfoDumper.cpp \
nsMessageLoop.cpp \
AvailableMemoryTracker.cpp \
$(NULL)
ifeq ($(OS_ARCH),Linux)
@ -93,8 +94,6 @@ CSRCS += pure_api.c
EXPORTS += pure.h
endif
CPPSRCS += AvailableMemoryTracker.cpp
endif #if OS_ARCH == WINNT
SDK_XPIDLSRCS = \