зеркало из https://github.com/mozilla/gecko-dev.git
Bug 903290 - Add a memory reporter for the observer service. r=njn
This commit is contained in:
Родитель
7ec6b9edf1
Коммит
990ec8e20c
|
@ -16,6 +16,10 @@
|
|||
#include "nsISimpleEnumerator.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
class ObserverServiceReporter;
|
||||
} // namespace mozilla
|
||||
|
||||
struct ObserverRef
|
||||
{
|
||||
ObserverRef(const ObserverRef& o) :
|
||||
|
@ -42,6 +46,8 @@ struct ObserverRef
|
|||
|
||||
class nsObserverList : public nsCharPtrHashKey
|
||||
{
|
||||
friend class mozilla::ObserverServiceReporter;
|
||||
|
||||
public:
|
||||
nsObserverList(const char *key) : nsCharPtrHashKey(key)
|
||||
{ MOZ_COUNT_CTOR(nsObserverList); }
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "mozilla/net/NeckoCommon.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#define NOTIFY_GLOBAL_OBSERVERS
|
||||
|
||||
|
@ -44,6 +46,159 @@ GetObserverServiceLog()
|
|||
#define LOG(x)
|
||||
#endif /* PR_LOGGING */
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ObserverServiceReporter MOZ_FINAL : public nsIMemoryMultiReporter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMEMORYMULTIREPORTER
|
||||
protected:
|
||||
static const size_t kSuspectReferentCount = 1000;
|
||||
static PLDHashOperator CountReferents(nsObserverList* aObserverList,
|
||||
void* aClosure);
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(ObserverServiceReporter, nsIMemoryMultiReporter)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObserverServiceReporter::GetName(nsACString& aName)
|
||||
{
|
||||
aName.AssignLiteral("observer-service");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
struct SuspectObserver {
|
||||
SuspectObserver(const char* aTopic, size_t aReferentCount)
|
||||
: topic(aTopic), referentCount(aReferentCount) {}
|
||||
const char* topic;
|
||||
size_t referentCount;
|
||||
};
|
||||
|
||||
struct ReferentCount {
|
||||
ReferentCount() : numStrong(0), numWeakAlive(0), numWeakDead(0) {}
|
||||
size_t numStrong;
|
||||
size_t numWeakAlive;
|
||||
size_t numWeakDead;
|
||||
nsTArray<SuspectObserver> suspectObservers;
|
||||
};
|
||||
|
||||
PLDHashOperator
|
||||
ObserverServiceReporter::CountReferents(nsObserverList* aObserverList,
|
||||
void* aClosure)
|
||||
{
|
||||
if (!aObserverList) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
ReferentCount* referentCount = static_cast<ReferentCount*>(aClosure);
|
||||
|
||||
size_t numStrong = 0;
|
||||
size_t numWeakAlive = 0;
|
||||
size_t numWeakDead = 0;
|
||||
|
||||
nsTArray<ObserverRef>& observers = aObserverList->mObservers;
|
||||
for (uint32_t i = 0; i < observers.Length(); i++) {
|
||||
if (observers[i].isWeakRef) {
|
||||
nsCOMPtr<nsIObserver> observerRef(
|
||||
do_QueryReferent(observers[i].asWeak()));
|
||||
if (observerRef) {
|
||||
numWeakAlive++;
|
||||
} else {
|
||||
numWeakDead++;
|
||||
}
|
||||
} else {
|
||||
numStrong++;
|
||||
}
|
||||
}
|
||||
|
||||
referentCount->numStrong += numStrong;
|
||||
referentCount->numWeakAlive += numWeakAlive;
|
||||
referentCount->numWeakDead += numWeakDead;
|
||||
|
||||
// Keep track of topics that have a suspiciously large number
|
||||
// of referents (symptom of leaks).
|
||||
size_t total = numStrong + numWeakAlive + numWeakDead;
|
||||
if (total > kSuspectReferentCount) {
|
||||
SuspectObserver suspect(aObserverList->GetKey(), total);
|
||||
referentCount->suspectObservers.AppendElement(suspect);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObserverServiceReporter::CollectReports(nsIMemoryMultiReporterCallback* cb,
|
||||
nsISupports* aClosure)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
nsObserverService* service = static_cast<nsObserverService*>(os.get());
|
||||
if (!service) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ReferentCount referentCount;
|
||||
service->mObserverTopicTable.EnumerateEntries(CountReferents,
|
||||
&referentCount);
|
||||
|
||||
nsresult rv;
|
||||
for (uint32_t i = 0; i < referentCount.suspectObservers.Length(); i++) {
|
||||
SuspectObserver& suspect = referentCount.suspectObservers[i];
|
||||
nsPrintfCString suspectPath("observer-service-suspect/"
|
||||
"referent(topic=%s)",
|
||||
suspect.topic);
|
||||
rv = cb->Callback(/* process */ EmptyCString(),
|
||||
suspectPath,
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_COUNT,
|
||||
suspect.referentCount,
|
||||
NS_LITERAL_CSTRING("A topic with a suspiciously large number "
|
||||
"referents (symptom of a leak)."),
|
||||
aClosure);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = cb->Callback(/* process */ EmptyCString(),
|
||||
NS_LITERAL_CSTRING("observer-service/referent/strong"),
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_COUNT,
|
||||
referentCount.numStrong,
|
||||
NS_LITERAL_CSTRING("The number of strong references held by the "
|
||||
"observer service."),
|
||||
aClosure);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = cb->Callback(/* process */ EmptyCString(),
|
||||
NS_LITERAL_CSTRING("observer-service/referent/weak/alive"),
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_COUNT,
|
||||
referentCount.numWeakAlive,
|
||||
NS_LITERAL_CSTRING("The number of weak references held by the "
|
||||
"observer service that are still alive."),
|
||||
aClosure);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = cb->Callback(/* process */ EmptyCString(),
|
||||
NS_LITERAL_CSTRING("observer-service/referent/weak/dead"),
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_COUNT,
|
||||
referentCount.numWeakDead,
|
||||
NS_LITERAL_CSTRING("The number of weak references held by the "
|
||||
"observer service that are dead."),
|
||||
aClosure);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsObserverService Implementation
|
||||
|
||||
|
@ -51,7 +206,7 @@ GetObserverServiceLog()
|
|||
NS_IMPL_ISUPPORTS2(nsObserverService, nsIObserverService, nsObserverService)
|
||||
|
||||
nsObserverService::nsObserverService() :
|
||||
mShuttingDown(false)
|
||||
mShuttingDown(false), mReporter(nullptr)
|
||||
{
|
||||
mObserverTopicTable.Init();
|
||||
}
|
||||
|
@ -61,9 +216,20 @@ nsObserverService::~nsObserverService(void)
|
|||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverService::RegisterReporter()
|
||||
{
|
||||
mReporter = new ObserverServiceReporter();
|
||||
NS_RegisterMemoryMultiReporter(mReporter);
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverService::Shutdown()
|
||||
{
|
||||
if (mReporter) {
|
||||
NS_UnregisterMemoryMultiReporter(mReporter);
|
||||
}
|
||||
|
||||
mShuttingDown = true;
|
||||
|
||||
if (mObserverTopicTable.IsInitialized())
|
||||
|
@ -80,6 +246,13 @@ nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstanc
|
|||
if (!os || !os->mObserverTopicTable.IsInitialized())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// The memory reporter can not be immediately registered here because
|
||||
// the nsMemoryReporterManager may attempt to get the nsObserverService
|
||||
// during initialization, causing a recursive GetService.
|
||||
nsRefPtr<nsRunnableMethod<nsObserverService> > registerRunnable =
|
||||
NS_NewRunnableMethod(os, &nsObserverService::RegisterReporter);
|
||||
NS_DispatchToCurrentThread(registerRunnable);
|
||||
|
||||
return os->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
|
@ -187,3 +360,4 @@ nsObserverService::UnmarkGrayStrongObservers()
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,15 @@
|
|||
#define NS_OBSERVERSERVICE_CID \
|
||||
{ 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } }
|
||||
|
||||
class nsIMemoryMultiReporter;
|
||||
|
||||
namespace mozilla {
|
||||
class ObserverServiceReporter;
|
||||
} // namespace mozilla
|
||||
|
||||
class nsObserverService MOZ_FINAL : public nsIObserverService {
|
||||
friend class mozilla::ObserverServiceReporter;
|
||||
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_OBSERVERSERVICE_CID)
|
||||
|
||||
|
@ -35,9 +43,11 @@ public:
|
|||
|
||||
private:
|
||||
~nsObserverService(void);
|
||||
void RegisterReporter();
|
||||
|
||||
bool mShuttingDown;
|
||||
nsTHashtable<nsObserverList> mObserverTopicTable;
|
||||
nsCOMPtr<nsIMemoryMultiReporter> mReporter;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsObserverService, NS_OBSERVERSERVICE_CID)
|
||||
|
|
Загрузка…
Ссылка в новой задаче