Bug 977940, part 1 - Don't run the ghost window detector more than every 45 seconds. r=smaug

This commit is contained in:
Andrew McCreight 2014-03-08 05:38:52 -08:00
Родитель 9d8a267db1
Коммит 260d421e2f
2 изменённых файлов: 78 добавлений и 24 удалений

Просмотреть файл

@ -24,11 +24,22 @@ using namespace mozilla;
StaticRefPtr<nsWindowMemoryReporter> sWindowReporter;
/**
* Don't trigger a ghost window check when a DOM window is detached if we've
* run it this recently.
*/
const int32_t kTimeBetweenChecks = 45; /* seconds */
nsWindowMemoryReporter::nsWindowMemoryReporter()
: mCheckForGhostWindowsCallbackPending(false)
: mLastCheckForGhostWindows(TimeStamp::NowLoRes())
{
}
nsWindowMemoryReporter::~nsWindowMemoryReporter()
{
KillCheckTimer();
}
NS_IMPL_ISUPPORTS3(nsWindowMemoryReporter, nsIMemoryReporter, nsIObserver,
nsSupportsWeakReference)
@ -626,12 +637,38 @@ nsWindowMemoryReporter::ObserveDOMWindowDetached(nsISupports* aWindow)
mDetachedWindows.Put(weakWindow, TimeStamp());
if (!mCheckForGhostWindowsCallbackPending) {
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this,
&nsWindowMemoryReporter::CheckForGhostWindowsCallback);
NS_DispatchToCurrentThread(runnable);
mCheckForGhostWindowsCallbackPending = true;
AsyncCheckForGhostWindows();
}
// static
void
nsWindowMemoryReporter::CheckTimerFired(nsITimer* aTimer, void* aClosure)
{
if (sWindowReporter) {
sWindowReporter->CheckForGhostWindows();
}
}
void
nsWindowMemoryReporter::AsyncCheckForGhostWindows()
{
if (mCheckTimer) {
return;
}
// If more than kTimeBetweenChecks seconds have elapsed since the last check,
// timerDelay is 0. Otherwise, it is kTimeBetweenChecks, reduced by the time
// since the last check. Reducing the delay by the time since the last check
// prevents the timer from being completely starved if it is repeatedly killed
// and restarted.
int32_t timeSinceLastCheck = (TimeStamp::NowLoRes() - mLastCheckForGhostWindows).ToSeconds();
int32_t timerDelay = (kTimeBetweenChecks - std::min(timeSinceLastCheck, kTimeBetweenChecks)) * PR_MSEC_PER_SEC;
CallCreateInstance<nsITimer>("@mozilla.org/timer;1", getter_AddRefs(mCheckTimer));
if (mCheckTimer) {
mCheckTimer->InitWithFuncCallback(CheckTimerFired, nullptr,
timerDelay, nsITimer::TYPE_ONE_SHOT);
}
}
@ -664,13 +701,6 @@ nsWindowMemoryReporter::ObserveAfterMinimizeMemoryUsage()
&minTimeStamp);
}
void
nsWindowMemoryReporter::CheckForGhostWindowsCallback()
{
mCheckForGhostWindowsCallbackPending = false;
CheckForGhostWindows();
}
struct CheckForGhostWindowsEnumeratorData
{
nsTHashtable<nsCStringHashKey> *nonDetachedDomains;
@ -808,6 +838,9 @@ nsWindowMemoryReporter::CheckForGhostWindows(
return;
}
mLastCheckForGhostWindows = TimeStamp::NowLoRes();
KillCheckTimer();
nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains;
// Populate nonDetachedWindowDomains.
@ -820,7 +853,7 @@ nsWindowMemoryReporter::CheckForGhostWindows(
// if it's not null.
CheckForGhostWindowsEnumeratorData ghostEnumData =
{ &nonDetachedWindowDomains, aOutGhostIDs, tldService,
GetGhostTimeout(), TimeStamp::Now() };
GetGhostTimeout(), mLastCheckForGhostWindows };
mDetachedWindows.Enumerate(CheckForGhostWindowsEnumerator,
&ghostEnumData);
}
@ -836,6 +869,15 @@ nsWindowMemoryReporter::GhostWindowsReporter::DistinguishedAmount()
return ghostWindows.Count();
}
void
nsWindowMemoryReporter::KillCheckTimer()
{
if (mCheckTimer) {
mCheckTimer->Cancel();
mCheckTimer = nullptr;
}
}
#ifdef DEBUG
static PLDHashOperator
UnlinkGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void *)

Просмотреть файл

@ -9,6 +9,7 @@
#include "nsIMemoryReporter.h"
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsDataHashtable.h"
#include "nsWeakReference.h"
#include "nsAutoPtr.h"
@ -139,6 +140,8 @@ public:
static void Init();
~nsWindowMemoryReporter();
#ifdef DEBUG
/**
* Unlink all known ghost windows, to enable investigating what caused them
@ -187,13 +190,6 @@ private:
void ObserveDOMWindowDetached(nsISupports* aWindow);
void ObserveAfterMinimizeMemoryUsage();
/**
* When we observe a DOM window being detached, we enqueue an asynchronous
* event which calls this method. This method then calls
* CheckForGhostWindows.
*/
void CheckForGhostWindowsCallback();
/**
* Iterate over all weak window pointers in mDetachedWindows and update our
* accounting of which windows meet ghost criterion (2).
@ -209,6 +205,19 @@ private:
*/
void CheckForGhostWindows(nsTHashtable<nsUint64HashKey> *aOutGhostIDs = nullptr);
/**
* Eventually do a check for ghost windows, if we haven't done one recently
* and we aren't already planning to do one soon.
*/
void AsyncCheckForGhostWindows();
/**
* Kill the check timer, if it exists.
*/
void KillCheckTimer();
static void CheckTimerFired(nsITimer* aTimer, void* aClosure);
/**
* Maps a weak reference to a detached window (nsIWeakReference) to the time
* when we observed that the window met ghost criterion (2) above.
@ -222,9 +231,12 @@ private:
nsDataHashtable<nsISupportsHashKey, mozilla::TimeStamp> mDetachedWindows;
/**
* True if we have an asynchronous call to CheckForGhostWindows pending.
* Track the last time we ran CheckForGhostWindows(), to avoid running it
* too often after a DOM window is detached.
*/
bool mCheckForGhostWindowsCallbackPending;
mozilla::TimeStamp mLastCheckForGhostWindows;
nsCOMPtr<nsITimer> mCheckTimer;
};
#endif // nsWindowMemoryReporter_h__