☠☠ backed out by 190eedf8577a ☠ ☠ | |
author | Nicholas Nethercote <nnethercote@mozilla.com> |
Thu, 07 Nov 2013 16:35:30 +1100 | |
changeset 173476 | 25312eb719988a0049a704813bb598ed07ed7177 |
parent 173475 | 6dbb8333960caaa9aca3dd63d5502025f4f0e9ca |
child 173477 | 85486c4aa3d8f54d69fa5c4a63098d8e5c347ac7 |
push id | 445 |
push user | ffxbld |
push date | Mon, 10 Mar 2014 22:05:19 +0000 |
treeherder | mozilla-release@dc38b741b04e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mccr8, bz |
bugs | 936964 |
milestone | 28.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -412,17 +412,17 @@ nsContentUtils::Init() if (!PL_DHashTableInit(&sEventListenerManagersHash, &hash_table_ops, nullptr, sizeof(EventListenerManagerMapEntry), 16)) { sEventListenerManagersHash.ops = nullptr; return NS_ERROR_OUT_OF_MEMORY; } - NS_RegisterMemoryReporter(new DOMEventListenerManagersHashReporter); + RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter()); } sBlockedScriptRunners = new nsTArray< nsCOMPtr<nsIRunnable> >; Preferences::AddBoolVarCache(&sAllowXULXBL_for_file, "dom.allow_XUL_XBL_for_file"); Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled,
--- a/content/base/src/nsDOMFile.cpp +++ b/content/base/src/nsDOMFile.cpp @@ -728,19 +728,17 @@ public: /* static */ void nsDOMMemoryFile::DataOwner::EnsureMemoryReporterRegistered() { sDataOwnerMutex.AssertCurrentThreadOwns(); if (sMemoryReporterRegistered) { return; } - nsRefPtr<nsDOMMemoryFileDataOwnerMemoryReporter> reporter = new - nsDOMMemoryFileDataOwnerMemoryReporter(); - NS_RegisterMemoryReporter(reporter); + RegisterStrongMemoryReporter(new nsDOMMemoryFileDataOwnerMemoryReporter()); sMemoryReporterRegistered = true; } //////////////////////////////////////////////////////////////////////////// // nsDOMFileList implementation NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsDOMFileList)
--- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -1295,17 +1295,17 @@ MessageManagerReporter::CollectReports(n nsresult NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult) { NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, NS_ERROR_NOT_AVAILABLE); nsFrameMessageManager* mm = new nsFrameMessageManager(nullptr, nullptr, MM_CHROME | MM_GLOBAL | MM_BROADCASTER); - NS_RegisterMemoryReporter(new MessageManagerReporter()); + RegisterStrongMemoryReporter(new MessageManagerReporter()); return CallQueryInterface(mm, aResult); } nsDataHashtable<nsStringHashKey, nsFrameJSScriptExecutorHolder*>* nsFrameScriptExecutor::sCachedScripts = nullptr; nsScriptCacheCleaner* nsFrameScriptExecutor::sScriptCacheCleaner = nullptr; void @@ -1830,17 +1830,17 @@ NS_NewChildProcessMessageManager(nsISync NS_ASSERTION(!nsFrameMessageManager::sChildProcessManager, "Re-creating sChildProcessManager"); MessageManagerCallback* cb; if (XRE_GetProcessType() == GeckoProcessType_Default) { cb = new SameChildProcessMessageManagerCallback(); } else { cb = new ChildProcessMessageManagerCallback(); - NS_RegisterMemoryReporter(new MessageManagerReporter()); + RegisterStrongMemoryReporter(new MessageManagerReporter()); } nsFrameMessageManager* mm = new nsFrameMessageManager(cb, nullptr, MM_PROCESSMANAGER | MM_OWNSCALLBACK); nsFrameMessageManager::sChildProcessManager = mm; return CallQueryInterface(mm, aResult); }
--- a/content/base/src/nsHostObjectProtocolHandler.cpp +++ b/content/base/src/nsHostObjectProtocolHandler.cpp @@ -48,17 +48,17 @@ class HostObjectURLsReporter MOZ_FINAL : } nsHostObjectProtocolHandler::nsHostObjectProtocolHandler() { static bool initialized = false; if (!initialized) { initialized = true; - NS_RegisterMemoryReporter(new mozilla::HostObjectURLsReporter()); + RegisterStrongMemoryReporter(new mozilla::HostObjectURLsReporter()); } } nsresult nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aScheme, nsISupports* aObject, nsIPrincipal* aPrincipal, nsACString& aUri)
--- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -883,17 +883,17 @@ CanvasRenderingContext2D::EnsureTarget() mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format); } } if (mTarget) { static bool registered = false; if (!registered) { registered = true; - NS_RegisterMemoryReporter(new Canvas2dPixelsReporter()); + RegisterStrongMemoryReporter(new Canvas2dPixelsReporter()); } gCanvasAzureMemoryUsed += mWidth * mHeight * 4; JSContext* context = nsContentUtils::GetCurrentJSContext(); if (context) { JS_updateMallocCounter(context, mWidth * mHeight * 4); }
--- a/content/canvas/src/WebGLContextReporter.cpp +++ b/content/canvas/src/WebGLContextReporter.cpp @@ -1,138 +1,122 @@ /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebGLContext.h" #include "WebGLMemoryTracker.h" -#include "nsIMemoryReporter.h" using namespace mozilla; NS_IMPL_ISUPPORTS1(WebGLMemoryPressureObserver, nsIObserver) -class WebGLMemoryReporter MOZ_FINAL : public MemoryMultiReporter -{ -public: - WebGLMemoryReporter() - : MemoryMultiReporter("webgl") - {} - - NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb, - nsISupports* aClosure); -}; - NS_IMETHODIMP -WebGLMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb, - nsISupports* aClosure) +WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData) { #define REPORT(_path, _kind, _units, _amount, _desc) \ do { \ nsresult rv; \ - rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), _kind, \ - _units, _amount, NS_LITERAL_CSTRING(_desc), \ - aClosure); \ + rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \ + _kind, _units, _amount, \ + NS_LITERAL_CSTRING(_desc), aData); \ NS_ENSURE_SUCCESS(rv, rv); \ } while (0) REPORT("webgl-texture-memory", - nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES, - WebGLMemoryTracker::GetTextureMemoryUsed(), + KIND_OTHER, UNITS_BYTES, GetTextureMemoryUsed(), "Memory used by WebGL textures.The OpenGL" " implementation is free to store these textures in either video" " memory or main memory. This measurement is only a lower bound," " actual memory usage may be higher for example if the storage" " is strided."); REPORT("webgl-texture-count", - nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT, - WebGLMemoryTracker::GetTextureCount(), + KIND_OTHER, UNITS_COUNT, GetTextureCount(), "Number of WebGL textures."); REPORT("webgl-buffer-memory", - nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES, - WebGLMemoryTracker::GetBufferMemoryUsed(), + KIND_OTHER, UNITS_BYTES, GetBufferMemoryUsed(), "Memory used by WebGL buffers. The OpenGL" " implementation is free to store these buffers in either video" " memory or main memory. This measurement is only a lower bound," " actual memory usage may be higher for example if the storage" " is strided."); REPORT("explicit/webgl/buffer-cache-memory", - nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, - WebGLMemoryTracker::GetBufferCacheMemoryUsed(), + KIND_HEAP, UNITS_BYTES, GetBufferCacheMemoryUsed(), "Memory used by WebGL buffer caches. The WebGL" " implementation caches the contents of element array buffers" " only.This adds up with the webgl-buffer-memory value, but" " contrary to it, this one represents bytes on the heap," " not managed by OpenGL."); REPORT("webgl-buffer-count", - nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT, - WebGLMemoryTracker::GetBufferCount(), + KIND_OTHER, UNITS_COUNT, GetBufferCount(), "Number of WebGL buffers."); REPORT("webgl-renderbuffer-memory", - nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES, - WebGLMemoryTracker::GetRenderbufferMemoryUsed(), + KIND_OTHER, UNITS_BYTES, GetRenderbufferMemoryUsed(), "Memory used by WebGL renderbuffers. The OpenGL" " implementation is free to store these renderbuffers in either" " video memory or main memory. This measurement is only a lower" " bound, actual memory usage may be higher for example if the" " storage is strided."); REPORT("webgl-renderbuffer-count", - nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT, - WebGLMemoryTracker::GetRenderbufferCount(), + KIND_OTHER, UNITS_COUNT, GetRenderbufferCount(), "Number of WebGL renderbuffers."); REPORT("explicit/webgl/shader", - nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, - WebGLMemoryTracker::GetShaderSize(), + KIND_HEAP, UNITS_BYTES, GetShaderSize(), "Combined size of WebGL shader ASCII sources and translation" " logs cached on the heap."); REPORT("webgl-shader-count", - nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT, - WebGLMemoryTracker::GetShaderCount(), + KIND_OTHER, UNITS_COUNT, GetShaderCount(), "Number of WebGL shaders."); REPORT("webgl-context-count", - nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT, - WebGLMemoryTracker::GetContextCount(), + KIND_OTHER, UNITS_COUNT, GetContextCount(), "Number of WebGL contexts."); #undef REPORT return NS_OK; } -NS_IMPL_ISUPPORTS1(WebGLMemoryTracker, nsISupports) +NS_IMPL_ISUPPORTS_INHERITED0(WebGLMemoryTracker, MemoryMultiReporter) StaticRefPtr<WebGLMemoryTracker> WebGLMemoryTracker::sUniqueInstance; WebGLMemoryTracker* WebGLMemoryTracker::UniqueInstance() { if (!sUniqueInstance) { sUniqueInstance = new WebGLMemoryTracker; + sUniqueInstance->InitMemoryReporter(); } return sUniqueInstance; } WebGLMemoryTracker::WebGLMemoryTracker() + : MemoryMultiReporter("webgl") { - mReporter = new WebGLMemoryReporter; - NS_RegisterMemoryReporter(mReporter); +} + +void +WebGLMemoryTracker::InitMemoryReporter() +{ + RegisterWeakMemoryReporter(this); } WebGLMemoryTracker::~WebGLMemoryTracker() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); } NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WebGLBufferMallocSizeOf) int64_t WebGLMemoryTracker::GetBufferCacheMemoryUsed() { const ContextsArrayType & contexts = Contexts(); int64_t result = 0;
--- a/content/canvas/src/WebGLMemoryTracker.h +++ b/content/canvas/src/WebGLMemoryTracker.h @@ -10,34 +10,35 @@ #include "WebGLBuffer.h" #include "WebGLVertexAttribData.h" #include "WebGLShader.h" #include "WebGLProgram.h" #include "WebGLUniformLocation.h" #include "WebGLTexture.h" #include "WebGLRenderbuffer.h" #include "mozilla/StaticPtr.h" +#include "nsIMemoryReporter.h" namespace mozilla { -class WebGLMemoryTracker : public nsISupports +class WebGLMemoryTracker : public MemoryMultiReporter { NS_DECL_ISUPPORTS WebGLMemoryTracker(); virtual ~WebGLMemoryTracker(); static StaticRefPtr<WebGLMemoryTracker> sUniqueInstance; - // here we store plain pointers, not RefPtrs: we don't want the + // Here we store plain pointers, not RefPtrs: we don't want the // WebGLMemoryTracker unique instance to keep alive all // WebGLContexts ever created. typedef nsTArray<const WebGLContext*> ContextsArrayType; ContextsArrayType mContexts; - nsCOMPtr<nsIMemoryReporter> mReporter; + void InitMemoryReporter(); static WebGLMemoryTracker* UniqueInstance(); static ContextsArrayType & Contexts() { return UniqueInstance()->mContexts; } friend class WebGLContext; public: @@ -49,16 +50,20 @@ class WebGLMemoryTracker : public nsISup static void RemoveWebGLContext(const WebGLContext* c) { ContextsArrayType & contexts = Contexts(); contexts.RemoveElement(c); if (contexts.IsEmpty()) { sUniqueInstance = nullptr; } } + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData); + + private: static int64_t GetTextureMemoryUsed() { const ContextsArrayType & contexts = Contexts(); int64_t result = 0; for(size_t i = 0; i < contexts.Length(); ++i) { for (const WebGLTexture *texture = contexts[i]->mTextures.getFirst(); texture; texture = texture->getNext()) {
--- a/content/media/MediaDecoder.cpp +++ b/content/media/MediaDecoder.cpp @@ -49,70 +49,63 @@ static const int64_t CAN_PLAY_THROUGH_MA #ifdef PR_LOGGING PRLogModuleInfo* gMediaDecoderLog; #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) #else #define DECODER_LOG(type, msg) #endif -class MediaMemoryTracker : public nsISupports +class MediaMemoryTracker : public MemoryMultiReporter { NS_DECL_ISUPPORTS MediaMemoryTracker(); virtual ~MediaMemoryTracker(); + void InitMemoryReporter(); + static StaticRefPtr<MediaMemoryTracker> sUniqueInstance; static MediaMemoryTracker* UniqueInstance() { if (!sUniqueInstance) { sUniqueInstance = new MediaMemoryTracker(); + sUniqueInstance->InitMemoryReporter(); } return sUniqueInstance; } typedef nsTArray<MediaDecoder*> DecodersArray; static DecodersArray& Decoders() { return UniqueInstance()->mDecoders; } DecodersArray mDecoders; - nsCOMPtr<nsIMemoryReporter> mReporter; - public: static void AddMediaDecoder(MediaDecoder* aDecoder) { Decoders().AppendElement(aDecoder); } static void RemoveMediaDecoder(MediaDecoder* aDecoder) { DecodersArray& decoders = Decoders(); decoders.RemoveElement(aDecoder); if (decoders.IsEmpty()) { sUniqueInstance = nullptr; } } - static void GetAmounts(int64_t* aVideo, int64_t* aAudio) - { - *aVideo = 0; - *aAudio = 0; - DecodersArray& decoders = Decoders(); - for (size_t i = 0; i < decoders.Length(); ++i) { - *aVideo += decoders[i]->VideoQueueMemoryInUse(); - *aAudio += decoders[i]->AudioQueueMemoryInUse(); - } - } + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData); }; StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance; -NS_IMPL_ISUPPORTS1(MediaMemoryTracker, nsISupports) +NS_IMPL_ISUPPORTS_INHERITED0(MediaMemoryTracker, MemoryMultiReporter) NS_IMPL_ISUPPORTS1(MediaDecoder, nsIObserver) void MediaDecoder::SetDormantIfNecessary(bool aDormant) { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); @@ -1771,61 +1764,62 @@ MediaDecoder::IsWMFEnabled() #ifdef MOZ_APPLEMEDIA bool MediaDecoder::IsAppleMP3Enabled() { return Preferences::GetBool("media.apple.mp3.enabled"); } #endif -class MediaReporter MOZ_FINAL : public MemoryMultiReporter +NS_IMETHODIMP +MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData) { -public: - MediaReporter() - : MemoryMultiReporter("media") - {} - - NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb, - nsISupports* aClosure) - { - int64_t video, audio; - MediaMemoryTracker::GetAmounts(&video, &audio); + int64_t video = 0, audio = 0; + DecodersArray& decoders = Decoders(); + for (size_t i = 0; i < decoders.Length(); ++i) { + video += decoders[i]->VideoQueueMemoryInUse(); + audio += decoders[i]->AudioQueueMemoryInUse(); + } - #define REPORT(_path, _amount, _desc) \ - do { \ - nsresult rv; \ - rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \ - nsIMemoryReporter::KIND_HEAP, \ - nsIMemoryReporter::UNITS_BYTES, _amount, \ - NS_LITERAL_CSTRING(_desc), aClosure); \ - NS_ENSURE_SUCCESS(rv, rv); \ - } while (0) +#define REPORT(_path, _amount, _desc) \ + do { \ + nsresult rv; \ + rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \ + KIND_HEAP, UNITS_BYTES, _amount, \ + NS_LITERAL_CSTRING(_desc), aData); \ + NS_ENSURE_SUCCESS(rv, rv); \ + } while (0) - REPORT("explicit/media/decoded-video", video, - "Memory used by decoded video frames."); + REPORT("explicit/media/decoded-video", video, + "Memory used by decoded video frames."); - REPORT("explicit/media/decoded-audio", audio, - "Memory used by decoded audio chunks."); + REPORT("explicit/media/decoded-audio", audio, + "Memory used by decoded audio chunks."); - return NS_OK; - } -}; + return NS_OK; +} MediaDecoderOwner* MediaDecoder::GetOwner() { MOZ_ASSERT(NS_IsMainThread()); return mOwner; } MediaMemoryTracker::MediaMemoryTracker() - : mReporter(new MediaReporter()) + : MemoryMultiReporter("media") { - NS_RegisterMemoryReporter(mReporter); +} + +void +MediaMemoryTracker::InitMemoryReporter() +{ + RegisterWeakMemoryReporter(this); } MediaMemoryTracker::~MediaMemoryTracker() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); } } // namespace mozilla
--- a/content/media/MediaDecoder.h +++ b/content/media/MediaDecoder.h @@ -186,17 +186,16 @@ destroying the MediaDecoder object. #include "mozilla/ReentrantMonitor.h" #include "mozilla/TimeStamp.h" #include "MediaStreamGraph.h" #include "AudioChannelCommon.h" #include "AbstractMediaDecoder.h" #include "necko-config.h" class nsIStreamListener; -class nsIMemoryReporter; class nsIPrincipal; class nsITimer; namespace mozilla { namespace dom { class TimeRanges; } }
--- a/dom/base/nsScriptNameSpaceManager.cpp +++ b/dom/base/nsScriptNameSpaceManager.cpp @@ -4,17 +4,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsScriptNameSpaceManager.h" #include "nsCOMPtr.h" #include "nsIComponentManager.h" #include "nsIComponentRegistrar.h" #include "nsICategoryManager.h" -#include "nsIMemoryReporter.h" #include "nsIServiceManager.h" #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsIScriptExternalNameSet.h" #include "nsIScriptNameSpaceManager.h" #include "nsIScriptContext.h" #include "nsIInterfaceInfoManager.h" #include "nsIInterfaceInfo.h" @@ -112,48 +111,35 @@ GlobalNameHashInitEntry(PLDHashTable *ta new (&e->mKey) nsString(*keyStr); // This will set e->mGlobalName.mType to // nsGlobalNameStruct::eTypeNotInitialized memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct)); return true; } -class ScriptNameSpaceManagerReporter MOZ_FINAL : public MemoryUniReporter -{ -public: - ScriptNameSpaceManagerReporter(nsScriptNameSpaceManager* aManager) - : MemoryUniReporter( - "explicit/script-namespace-manager", - KIND_HEAP, - nsIMemoryReporter::UNITS_BYTES, - "Memory used for the script namespace manager.") - , mManager(aManager) - {} - -private: - int64_t Amount() { return mManager->SizeOfIncludingThis(MallocSizeOf); } - - nsScriptNameSpaceManager* mManager; -}; - -NS_IMPL_ISUPPORTS2(nsScriptNameSpaceManager, - nsIObserver, - nsISupportsWeakReference) +NS_IMPL_ISUPPORTS_INHERITED2( + nsScriptNameSpaceManager, + MemoryUniReporter, + nsIObserver, + nsISupportsWeakReference) nsScriptNameSpaceManager::nsScriptNameSpaceManager() - : mIsInitialized(false) + : MemoryUniReporter("explicit/script-namespace-manager", + KIND_HEAP, UNITS_BYTES, + "Memory used for the script namespace manager.") + , mIsInitialized(false) { MOZ_COUNT_CTOR(nsScriptNameSpaceManager); } nsScriptNameSpaceManager::~nsScriptNameSpaceManager() { if (mIsInitialized) { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); // Destroy the hash PL_DHashTableFinish(&mGlobalNames); PL_DHashTableFinish(&mNavigatorNames); } MOZ_COUNT_DTOR(nsScriptNameSpaceManager); } nsGlobalNameStruct * @@ -358,18 +344,17 @@ nsScriptNameSpaceManager::Init() sizeof(GlobalNameMapEntry), GLOBALNAME_HASHTABLE_INITIAL_SIZE); if (!mIsInitialized) { PL_DHashTableFinish(&mGlobalNames); return NS_ERROR_OUT_OF_MEMORY; } - mReporter = new ScriptNameSpaceManagerReporter(this); - NS_RegisterMemoryReporter(mReporter); + RegisterWeakMemoryReporter(this); nsresult rv = NS_OK; rv = RegisterExternalInterfaces(false); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsICategoryManager> cm = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); @@ -877,18 +862,24 @@ nsScriptNameSpaceManager::EnumerateNavig static size_t SizeOfEntryExcludingThis(PLDHashEntryHdr *aHdr, MallocSizeOf aMallocSizeOf, void *aArg) { GlobalNameMapEntry* entry = static_cast<GlobalNameMapEntry*>(aHdr); return entry->SizeOfExcludingThis(aMallocSizeOf); } +int64_t +nsScriptNameSpaceManager::Amount() +{ + return SizeOfIncludingThis(MallocSizeOf); +} + size_t -nsScriptNameSpaceManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) +nsScriptNameSpaceManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { size_t n = 0; n += PL_DHashTableSizeOfExcludingThis(&mGlobalNames, SizeOfEntryExcludingThis, aMallocSizeOf); n += PL_DHashTableSizeOfExcludingThis(&mNavigatorNames, SizeOfEntryExcludingThis, aMallocSizeOf); return n; }
--- a/dom/base/nsScriptNameSpaceManager.h +++ b/dom/base/nsScriptNameSpaceManager.h @@ -17,16 +17,17 @@ * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink * use in OS2 */ #ifndef nsScriptNameSpaceManager_h__ #define nsScriptNameSpaceManager_h__ #include "mozilla/MemoryReporting.h" +#include "nsIMemoryReporter.h" #include "nsIScriptNameSpaceManager.h" #include "nsString.h" #include "nsID.h" #include "pldhash.h" #include "nsDOMClassInfo.h" #include "nsIObserver.h" #include "nsWeakReference.h" #include "xpcpublic.h" @@ -79,21 +80,21 @@ struct nsGlobalNameStruct }; // May be null if enabled unconditionally mozilla::dom::ConstructorEnabled* mConstructorEnabled; }; class nsIScriptContext; class nsICategoryManager; -class nsIMemoryReporter; class GlobalNameMapEntry; -class nsScriptNameSpaceManager : public nsIObserver, +class nsScriptNameSpaceManager : public mozilla::MemoryUniReporter, + public nsIObserver, public nsSupportsWeakReference { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER nsScriptNameSpaceManager(); virtual ~nsScriptNameSpaceManager(); @@ -157,16 +158,17 @@ public: typedef PLDHashOperator (* NameEnumerator)(const nsAString& aGlobalName, void* aClosure); void EnumerateGlobalNames(NameEnumerator aEnumerator, void* aClosure); void EnumerateNavigatorNames(NameEnumerator aEnumerator, void* aClosure); + int64_t Amount() MOZ_OVERRIDE; size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); private: // Adds a new entry to the hash and returns the nsGlobalNameStruct // that aKey will be mapped to. If mType in the returned // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey // already existed. nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const nsAString *aKey, @@ -219,13 +221,11 @@ private: nsGlobalNameStruct* LookupNameInternal(const nsAString& aName, const PRUnichar **aClassName = nullptr); PLDHashTable mGlobalNames; PLDHashTable mNavigatorNames; bool mIsInitialized; - - nsCOMPtr<nsIMemoryReporter> mReporter; }; #endif /* nsScriptNameSpaceManager_h__ */
--- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -89,30 +89,30 @@ NonJSSizeOfTab(nsPIDOMWindow* aWindow, s } /* static */ void nsWindowMemoryReporter::Init() { MOZ_ASSERT(!sWindowReporter); sWindowReporter = new nsWindowMemoryReporter(); ClearOnShutdown(&sWindowReporter); - NS_RegisterMemoryReporter(sWindowReporter); + RegisterStrongMemoryReporter(sWindowReporter); RegisterNonJSSizeOfTab(NonJSSizeOfTab); nsCOMPtr<nsIObserverService> os = services::GetObserverService(); if (os) { // DOM_WINDOW_DESTROYED_TOPIC announces what we call window "detachment", // when a window's docshell is set to nullptr. os->AddObserver(sWindowReporter, DOM_WINDOW_DESTROYED_TOPIC, /* weakRef = */ true); os->AddObserver(sWindowReporter, "after-minimize-memory-usage", /* weakRef = */ true); } - NS_RegisterMemoryReporter(new GhostWindowsReporter()); + RegisterStrongMemoryReporter(new GhostWindowsReporter()); RegisterGhostWindowsDistinguishedAmount(GhostWindowsReporter::DistinguishedAmount); } static already_AddRefed<nsIURI> GetWindowURI(nsIDOMWindow *aWindow) { nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aWindow); NS_ENSURE_TRUE(pWindow, nullptr);
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -332,17 +332,18 @@ ContentParent::MaybeTakePreallocatedAppP /*static*/ void ContentParent::StartUp() { if (XRE_GetProcessType() != GeckoProcessType_Default) { return; } - NS_RegisterMemoryReporter(new ContentParentsMemoryReporter()); + // Note: This reporter measures all ContentParents. + RegisterStrongMemoryReporter(new ContentParentsMemoryReporter()); sCanLaunchSubprocesses = true; // Try to preallocate a process that we can transform into an app later. PreallocatedProcessManager::AllocateAfterDelay(); } /*static*/ void
--- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -4018,17 +4018,17 @@ void WorkerPrivate::EnableMemoryReporter() { AssertIsOnWorkerThread(); // No need to lock here since the main thread can't race until we've // successfully registered the reporter. mMemoryReporter = new MemoryReporter(this); - if (NS_FAILED(NS_RegisterMemoryReporter(mMemoryReporter))) { + if (NS_FAILED(RegisterWeakMemoryReporter(mMemoryReporter))) { NS_WARNING("Failed to register memory reporter!"); // No need to lock here since a failed registration means our memory // reporter can't start running. Just clean up. mMemoryReporter = nullptr; return; } } @@ -4073,17 +4073,17 @@ WorkerPrivate::DisableMemoryReporter() } NS_ASSERTION(mBlockedForMemoryReporter, "Somehow we got unblocked!"); mBlockedForMemoryReporter = false; } } // Finally unregister the memory reporter. - if (NS_FAILED(NS_UnregisterMemoryReporter(memoryReporter))) { + if (NS_FAILED(UnregisterWeakMemoryReporter(memoryReporter))) { NS_WARNING("Failed to unregister memory reporter!"); } } void WorkerPrivate::WaitForWorkerEvents(PRIntervalTime aInterval) { AssertIsOnWorkerThread();
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp +++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp @@ -69,93 +69,81 @@ #include "mozISpellI18NManager.h" #include "nsICharsetConverterManager.h" #include "nsUnicharUtilCIID.h" #include "nsUnicharUtils.h" #include "nsCRT.h" #include "mozInlineSpellChecker.h" #include "mozilla/Services.h" #include <stdlib.h> -#include "nsIMemoryReporter.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID); NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell) NS_IMPL_CYCLE_COLLECTING_RELEASE(mozHunspell) NS_INTERFACE_MAP_BEGIN(mozHunspell) + NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter) NS_INTERFACE_MAP_ENTRY(mozISpellCheckingEngine) NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozISpellCheckingEngine) NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozHunspell) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_3(mozHunspell, mPersonalDictionary, mEncoder, mDecoder) -class SpellCheckReporter MOZ_FINAL : public mozilla::MemoryUniReporter -{ -public: - SpellCheckReporter() - : MemoryUniReporter("explicit/spell-check", KIND_HEAP, UNITS_BYTES, -"Memory used by the Hunspell spell checking engine's internal data structures.") - { -#ifdef DEBUG - // There must be only one instance of this class, due to |sAmount| - // being static. - static bool hasRun = false; - MOZ_ASSERT(!hasRun); - hasRun = true; -#endif - } - - static void OnAlloc(void* ptr) { sAmount += MallocSizeOfOnAlloc(ptr); } - static void OnFree (void* ptr) { sAmount -= MallocSizeOfOnFree (ptr); } - -private: - int64_t Amount() MOZ_OVERRIDE { return sAmount; } - - static int64_t sAmount; -}; - -int64_t SpellCheckReporter::sAmount = 0; +int64_t mozHunspell::sAmount = 0; // WARNING: hunspell_alloc_hooks.h uses these two functions. void HunspellReportMemoryAllocation(void* ptr) { - SpellCheckReporter::OnAlloc(ptr); + mozHunspell::OnAlloc(ptr); } void HunspellReportMemoryDeallocation(void* ptr) { - SpellCheckReporter::OnFree(ptr); + mozHunspell::OnFree(ptr); +} + +mozHunspell::mozHunspell() + : MemoryUniReporter("explicit/spell-check", KIND_HEAP, UNITS_BYTES, +"Memory used by the spell-checking engine's internal data structures."), + mHunspell(nullptr) +{ +#ifdef DEBUG + // There must be only one instance of this class, due to |sAmount| + // being static. + static bool hasRun = false; + MOZ_ASSERT(!hasRun); + hasRun = true; +#endif } nsresult mozHunspell::Init() { LoadDictionaryList(); nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (obs) { obs->AddObserver(this, "profile-do-change", true); obs->AddObserver(this, "profile-after-change", true); } - mReporter = new SpellCheckReporter(); - NS_RegisterMemoryReporter(mReporter); + RegisterWeakMemoryReporter(this); return NS_OK; } mozHunspell::~mozHunspell() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); mPersonalDictionary = nullptr; delete mHunspell; } /* attribute wstring dictionary; */ NS_IMETHODIMP mozHunspell::GetDictionary(PRUnichar **aDictionary) {
--- a/extensions/spellcheck/hunspell/src/mozHunspell.h +++ b/extensions/spellcheck/hunspell/src/mozHunspell.h @@ -61,64 +61,69 @@ #define mozHunspell_h__ #include <hunspell.hxx> #include "mozISpellCheckingEngine.h" #include "mozIPersonalDictionary.h" #include "nsString.h" #include "nsCOMPtr.h" #include "nsCOMArray.h" +#include "nsIMemoryReporter.h" #include "nsIObserver.h" #include "nsIUnicodeEncoder.h" #include "nsIUnicodeDecoder.h" #include "nsInterfaceHashtable.h" #include "nsWeakReference.h" #include "nsCycleCollectionParticipant.h" #define MOZ_HUNSPELL_CONTRACTID "@mozilla.org/spellchecker/engine;1" #define MOZ_HUNSPELL_CID \ /* 56c778e4-1bee-45f3-a689-886692a97fe7 */ \ { 0x56c778e4, 0x1bee, 0x45f3, \ { 0xa6, 0x89, 0x88, 0x66, 0x92, 0xa9, 0x7f, 0xe7 } } -class nsIMemoryReporter; - -class mozHunspell : public mozISpellCheckingEngine, - public nsIObserver, - public nsSupportsWeakReference +class mozHunspell : public mozilla::MemoryUniReporter, + public mozISpellCheckingEngine, + public nsIObserver, + public nsSupportsWeakReference { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_MOZISPELLCHECKINGENGINE NS_DECL_NSIOBSERVER NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozHunspell, mozISpellCheckingEngine) - mozHunspell() : mHunspell(nullptr) { } + mozHunspell(); virtual ~mozHunspell(); nsresult Init(); void LoadDictionaryList(); // helper method for converting a word to the charset of the dictionary nsresult ConvertCharset(const PRUnichar* aStr, char ** aDst); + static void OnAlloc(void* ptr) { sAmount += MallocSizeOfOnAlloc(ptr); } + static void OnFree (void* ptr) { sAmount -= MallocSizeOfOnFree (ptr); } + + int64_t Amount() MOZ_OVERRIDE { return sAmount; } + protected: - + nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary; - nsCOMPtr<nsIUnicodeEncoder> mEncoder; - nsCOMPtr<nsIUnicodeDecoder> mDecoder; + nsCOMPtr<nsIUnicodeEncoder> mEncoder; + nsCOMPtr<nsIUnicodeDecoder> mDecoder; // Hashtable matches dictionary name to .aff file nsInterfaceHashtable<nsStringHashKey, nsIFile> mDictionaries; nsString mDictionary; nsString mLanguage; nsCString mAffixFileName; // dynamic dirs used to search for dictionaries nsCOMArray<nsIFile> mDynamicDirectories; Hunspell *mHunspell; - nsCOMPtr<nsIMemoryReporter> mReporter; + static int64_t sAmount; }; #endif
--- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -1232,17 +1232,17 @@ GLContext::CanReadSRGBFromFBOTexture() bool GLContext::sPowerOfTwoForced = false; bool GLContext::sPowerOfTwoPrefCached = false; void GLContext::PlatformStartup() { CacheCanUploadNPOT(); - NS_RegisterMemoryReporter(new GfxTexturesReporter()); + RegisterStrongMemoryReporter(new GfxTexturesReporter()); } void GLContext::CacheCanUploadNPOT() { MOZ_ASSERT(NS_IsMainThread(), "Can't cache prefs off the main thread."); MOZ_ASSERT(!sPowerOfTwoPrefCached, "Must only call this function once!");
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp +++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp @@ -220,17 +220,17 @@ GrallocBufferActor::GrallocBufferActor() : mAllocBytes(0) { static bool registered; if (!registered) { // We want to be sure that the first call here will always run on // the main thread. NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_RegisterMemoryReporter(new GrallocReporter()); + RegisterStrongMemoryReporter(new GrallocReporter()); registered = true; } } GrallocBufferActor::~GrallocBufferActor() { if (mAllocBytes > 0) { GrallocReporter::sAmount -= mAllocBytes;
--- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -671,17 +671,17 @@ gfxASurface::RecordMemoryUsedForSurfaceT { if (aType < 0 || aType >= gfxSurfaceTypeMax) { NS_WARNING("Invalid type to RecordMemoryUsedForSurfaceType!"); return; } static bool registered = false; if (!registered) { - NS_RegisterMemoryReporter(new SurfaceMemoryReporter()); + RegisterStrongMemoryReporter(new SurfaceMemoryReporter()); registered = true; } gSurfaceMemoryUsed[aType] += aBytes; } void gfxASurface::RecordMemoryUsed(int32_t aBytes)
--- a/gfx/thebes/gfxAndroidPlatform.cpp +++ b/gfx/thebes/gfxAndroidPlatform.cpp @@ -92,18 +92,17 @@ gfxAndroidPlatform::gfxAndroidPlatform() sFreetypeMemoryRecord.free = FreetypeReporter::CountingFree; sFreetypeMemoryRecord.realloc = FreetypeReporter::CountingRealloc; // These two calls are equivalent to FT_Init_FreeType(), but allow us to // provide a custom memory allocator. FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary); FT_Add_Default_Modules(gPlatformFTLibrary); - mFreetypeReporter = new FreetypeReporter(); - NS_RegisterMemoryReporter(mFreetypeReporter); + RegisterStrongMemoryReporter(new FreetypeReporter()); nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1"); nsCOMPtr<nsIScreen> screen; screenMgr->GetPrimaryScreen(getter_AddRefs(screen)); mScreenDepth = 24; screen->GetColorDepth(&mScreenDepth); mOffscreenFormat = mScreenDepth == 16 @@ -115,18 +114,16 @@ gfxAndroidPlatform::gfxAndroidPlatform() } } gfxAndroidPlatform::~gfxAndroidPlatform() { cairo_debug_reset_static_data(); - NS_UnregisterMemoryReporter(mFreetypeReporter); - FT_Done_Library(gPlatformFTLibrary); gPlatformFTLibrary = nullptr; } already_AddRefed<gfxASurface> gfxAndroidPlatform::CreateOffscreenSurface(const gfxIntSize& size, gfxContentType contentType) {
--- a/gfx/thebes/gfxAndroidPlatform.h +++ b/gfx/thebes/gfxAndroidPlatform.h @@ -76,14 +76,12 @@ public: FT_Library GetFTLibrary(); virtual int GetScreenDepth() const; private: int mScreenDepth; gfxImageFormat mOffscreenFormat; - - nsCOMPtr<nsIMemoryReporter> mFreetypeReporter; }; #endif /* GFX_PLATFORM_ANDROID_H */
--- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -1410,17 +1410,17 @@ gfxFontCache::Observer::Observe(nsISuppo nsresult gfxFontCache::Init() { NS_ASSERTION(!gGlobalCache, "Where did this come from?"); gGlobalCache = new gfxFontCache(); if (!gGlobalCache) { return NS_ERROR_OUT_OF_MEMORY; } - NS_RegisterMemoryReporter(new MemoryReporter); + RegisterStrongMemoryReporter(new MemoryReporter()); return NS_OK; } void gfxFontCache::Shutdown() { delete gGlobalCache; gGlobalCache = nullptr;
--- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -497,17 +497,17 @@ gfxPlatform::Init() // Listen to memory pressure event so we can purge DrawTarget caches nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); if (obs) { gPlatform->mMemoryPressureObserver = new MemoryPressureObserver(); obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false); } - NS_RegisterMemoryReporter(new GfxMemoryImageReporter()); + RegisterStrongMemoryReporter(new GfxMemoryImageReporter()); } void gfxPlatform::Shutdown() { // These may be called before the corresponding subsystems have actually // started up. That's OK, they can handle it. gfxFontCache::Shutdown();
--- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -132,17 +132,17 @@ gfxPlatformFontList::gfxPlatformFontList // pref changes notification setup NS_ASSERTION(!gFontListPrefObserver, "There has been font list pref observer already"); gFontListPrefObserver = new gfxFontListPrefObserver(); NS_ADDREF(gFontListPrefObserver); Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs); - NS_RegisterMemoryReporter(new MemoryReporter); + RegisterStrongMemoryReporter(new MemoryReporter()); } gfxPlatformFontList::~gfxPlatformFontList() { mSharedCmaps.Clear(); NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer"); Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs); NS_RELEASE(gFontListPrefObserver);
--- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -361,36 +361,32 @@ gfxWindowsPlatform::gfxWindowsPlatform() /* * Initialize COM */ CoInitialize(nullptr); mScreenDC = GetDC(nullptr); #ifdef CAIRO_HAS_D2D_SURFACE - NS_RegisterMemoryReporter(new GfxD2DSurfaceCacheReporter()); - NS_RegisterMemoryReporter(new GfxD2DSurfaceVramReporter()); + RegisterStrongMemoryReporter(new GfxD2DSurfaceCacheReporter()); + RegisterStrongMemoryReporter(new GfxD2DSurfaceVramReporter()); mD2DDevice = nullptr; #endif - NS_RegisterMemoryReporter(new GfxD2DVramDrawTargetReporter()); - NS_RegisterMemoryReporter(new GfxD2DVramSourceSurfaceReporter()); + RegisterStrongMemoryReporter(new GfxD2DVramDrawTargetReporter()); + RegisterStrongMemoryReporter(new GfxD2DVramSourceSurfaceReporter()); UpdateRenderMode(); // This reporter is disabled because it frequently gives bogus values. See // bug 917496. - //mGPUAdapterReporter = new GPUAdapterReporter(); - //NS_RegisterMemoryReporter(mGPUAdapterReporter); - mGPUAdapterReporter = nullptr; + //RegisterStrongMemoryReporter(new GPUAdapterReporter()); } gfxWindowsPlatform::~gfxWindowsPlatform() { - //NS_UnregisterMemoryReporter(mGPUAdapterReporter); - mDeviceManager = nullptr; ::ReleaseDC(nullptr, mScreenDC); // not calling FT_Done_FreeType because cairo may still hold references to // these FT_Faces. See bug 458169. #ifdef CAIRO_HAS_D2D_SURFACE if (mD2DDevice) { cairo_release_device(mD2DDevice);
--- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -296,13 +296,11 @@ private: nsRefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager; mozilla::RefPtr<ID3D11Device> mD3D11Device; bool mD3D11DeviceInitialized; virtual qcms_profile* GetPlatformCMSOutputProfile(); // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts; - - nsIMemoryReporter* mGPUAdapterReporter; }; #endif /* GFX_WINDOWS_PLATFORM_H */
--- a/image/src/SurfaceCache.cpp +++ b/image/src/SurfaceCache.cpp @@ -219,44 +219,48 @@ private: /* * SurfaceCacheImpl is responsible for determining which surfaces will be cached * and managing the surface cache data structures. Rather than interact with * SurfaceCacheImpl directly, client code interacts with SurfaceCache, which * maintains high-level invariants and encapsulates the details of the surface * cache's implementation. */ -class SurfaceCacheImpl : public nsISupports +class SurfaceCacheImpl : public MemoryUniReporter { public: NS_DECL_ISUPPORTS SurfaceCacheImpl(uint32_t aSurfaceCacheExpirationTimeMS, uint32_t aSurfaceCacheSize) - : mExpirationTracker(MOZ_THIS_IN_INITIALIZER_LIST(), + : MemoryUniReporter("imagelib-surface-cache", + KIND_OTHER, UNITS_BYTES, + "Memory used by the imagelib temporary surface cache.") + , mExpirationTracker(MOZ_THIS_IN_INITIALIZER_LIST(), aSurfaceCacheExpirationTimeMS) - , mReporter(new SurfaceCacheReporter) , mMemoryPressureObserver(new MemoryPressureObserver) , mMaxCost(aSurfaceCacheSize) , mAvailableCost(aSurfaceCacheSize) { - NS_RegisterMemoryReporter(mReporter); - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); if (os) os->AddObserver(mMemoryPressureObserver, "memory-pressure", false); } virtual ~SurfaceCacheImpl() { nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); if (os) os->RemoveObserver(mMemoryPressureObserver, "memory-pressure"); - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); + } + + void InitMemoryReporter() { + RegisterWeakMemoryReporter(this); } void Insert(DrawTarget* aTarget, nsIntSize aTargetSize, const Cost aCost, const ImageKey aImageKey, const SurfaceKey& aSurfaceKey) { @@ -380,19 +384,28 @@ public: static PLDHashOperator DoStopTracking(const SurfaceKey&, CachedSurface* aSurface, void* aCache) { static_cast<SurfaceCacheImpl*>(aCache)->StopTracking(aSurface); return PL_DHASH_NEXT; } - int64_t SizeOfSurfacesEstimate() const + int64_t Amount() MOZ_OVERRIDE { - return int64_t(mMaxCost - mAvailableCost); + return SizeOfSurfacesEstimate(); + } + + // XXX(seth): This is currently only an estimate and, since we don't know + // which surfaces are in GPU memory and which aren't, it's reported as + // KIND_OTHER and will also show up in heap-unclassified. Bug 923302 will + // make this nicer. + Cost SizeOfSurfacesEstimate() const + { + return mMaxCost - mAvailableCost; } private: already_AddRefed<ImageSurfaceCache> GetImageCache(const ImageKey aImageKey) { nsRefPtr<ImageSurfaceCache> imageCache; mImageCaches.Get(aImageKey, getter_AddRefs(imageCache)); return imageCache.forget(); @@ -412,35 +425,16 @@ private: mCache->Remove(aSurface); } } private: SurfaceCacheImpl* const mCache; // Weak pointer to owner. }; - // XXX(seth): This is currently only an estimate and, since we don't know which - // surfaces are in GPU memory and which aren't, it's reported as KIND_OTHER and - // will also show up in heap-unclassified. Bug 923302 will make this nicer. - struct SurfaceCacheReporter : public MemoryUniReporter - { - SurfaceCacheReporter() - : MemoryUniReporter("imagelib-surface-cache", - KIND_OTHER, - UNITS_BYTES, - "Memory used by the imagelib temporary surface cache.") - { } - - protected: - int64_t Amount() MOZ_OVERRIDE - { - return sInstance ? sInstance->SizeOfSurfacesEstimate() : 0; - } - }; - struct MemoryPressureObserver : public nsIObserver { NS_DECL_ISUPPORTS virtual ~MemoryPressureObserver() { } NS_IMETHOD Observe(nsISupports*, const char* aTopic, const PRUnichar*) { @@ -450,23 +444,22 @@ private: return NS_OK; } }; nsTArray<CostEntry> mCosts; nsRefPtrHashtable<nsPtrHashKey<Image>, ImageSurfaceCache> mImageCaches; SurfaceTracker mExpirationTracker; - nsRefPtr<SurfaceCacheReporter> mReporter; nsRefPtr<MemoryPressureObserver> mMemoryPressureObserver; const Cost mMaxCost; Cost mAvailableCost; }; -NS_IMPL_ISUPPORTS1(SurfaceCacheImpl, nsISupports) +NS_IMPL_ISUPPORTS_INHERITED0(SurfaceCacheImpl, MemoryUniReporter) NS_IMPL_ISUPPORTS1(SurfaceCacheImpl::MemoryPressureObserver, nsIObserver) /////////////////////////////////////////////////////////////////////////////// // Public API /////////////////////////////////////////////////////////////////////////////// /* static */ void SurfaceCache::Initialize() @@ -501,16 +494,17 @@ SurfaceCache::Initialize() uint32_t proposedSize = PR_GetPhysicalMemorySize() / surfaceCacheSizeFactor; uint32_t surfaceCacheSizeBytes = min(proposedSize, surfaceCacheMaxSizeKB * 1024); // Create the surface cache singleton with the requested expiration time and // size. Note that the size is a limit that the cache may not grow beyond, but // we do not actually allocate any storage for surfaces at this time. sInstance = new SurfaceCacheImpl(surfaceCacheExpirationTimeMS, surfaceCacheSizeBytes); + sInstance->InitMemoryReporter(); } /* static */ void SurfaceCache::Shutdown() { MOZ_ASSERT(sInstance, "No singleton - was Shutdown() called twice?"); sInstance = nullptr; }
--- a/image/src/imgLoader.cpp +++ b/image/src/imgLoader.cpp @@ -815,17 +815,17 @@ void imgLoader::GlobalInit() int32_t cachesize; rv = Preferences::GetInt("image.cache.size", &cachesize); if (NS_SUCCEEDED(rv)) sCacheMaxSize = cachesize; else sCacheMaxSize = 5 * 1024 * 1024; sMemReporter = new imgMemoryReporter(); - NS_RegisterMemoryReporter(sMemReporter); + RegisterStrongMemoryReporter(sMemReporter); RegisterImagesContentUsedUncompressedDistinguishedAmount(imgMemoryReporter::ImagesContentUsedUncompressedDistinguishedAmount); } nsresult imgLoader::InitCache() { nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); if (!os) return NS_ERROR_FAILURE;
--- a/ipc/glue/SharedMemory.cpp +++ b/ipc/glue/SharedMemory.cpp @@ -41,18 +41,18 @@ private: }; SharedMemory::SharedMemory() : mAllocSize(0) , mMappedSize(0) { static Atomic<uint32_t> registered; if (registered.compareExchange(0, 1)) { - NS_RegisterMemoryReporter(new ShmemAllocatedReporter()); - NS_RegisterMemoryReporter(new ShmemMappedReporter()); + RegisterStrongMemoryReporter(new ShmemAllocatedReporter()); + RegisterStrongMemoryReporter(new ShmemMappedReporter()); } } /*static*/ size_t SharedMemory::PageAlignedSize(size_t aSize) { size_t pageSize = SystemPageSize(); size_t nPagesNeeded = size_t(ceil(double(aSize) / double(pageSize)));
--- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -3091,18 +3091,18 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* // Set up locale information and callbacks for the newly-created runtime so // that the various toLocaleString() methods, localeCompare(), and other // internationalization APIs work as desired. if (!xpc_LocalizeRuntime(runtime)) NS_RUNTIMEABORT("xpc_LocalizeRuntime failed."); // Register memory reporters and distinguished amount functions. - NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsReporter); - NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter()); + RegisterStrongMemoryReporter(new JSMainRuntimeCompartmentsReporter()); + RegisterStrongMemoryReporter(new JSMainRuntimeTemporaryPeakReporter()); RegisterJSMainRuntimeGCHeapDistinguishedAmount(JSMainRuntimeGCHeapDistinguishedAmount); RegisterJSMainRuntimeTemporaryPeakDistinguishedAmount(JSMainRuntimeTemporaryPeakDistinguishedAmount); RegisterJSMainRuntimeCompartmentsSystemDistinguishedAmount(JSMainRuntimeCompartmentsSystemDistinguishedAmount); RegisterJSMainRuntimeCompartmentsUserDistinguishedAmount(JSMainRuntimeCompartmentsUserDistinguishedAmount); mozilla::RegisterJSSizeOfTab(JSSizeOfTab); // Install a JavaScript 'debugger' keyword handler in debug builds only #ifdef DEBUG
--- a/layout/base/nsStyleSheetService.cpp +++ b/layout/base/nsStyleSheetService.cpp @@ -16,60 +16,42 @@ #include "nsCSSStyleSheet.h" #include "nsIURI.h" #include "nsCOMPtr.h" #include "nsICategoryManager.h" #include "nsISupportsPrimitives.h" #include "nsNetUtil.h" #include "nsIObserverService.h" #include "nsLayoutStatics.h" -#include "nsIMemoryReporter.h" using namespace mozilla; -class LayoutStyleSheetServiceReporter MOZ_FINAL - : public mozilla::MemoryUniReporter -{ -public: - LayoutStyleSheetServiceReporter() - : MemoryUniReporter("explicit/layout/style-sheet-service", - KIND_HEAP, UNITS_BYTES, -"Memory used for style sheets held by the style sheet service.") - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - return nsStyleSheetService::gInstance - ? nsStyleSheetService::gInstance->SizeOfIncludingThis(MallocSizeOf) - : 0; - } -}; - nsStyleSheetService *nsStyleSheetService::gInstance = nullptr; nsStyleSheetService::nsStyleSheetService() + : MemoryUniReporter("explicit/layout/style-sheet-service", + KIND_HEAP, UNITS_BYTES, +"Memory used for style sheets held by the style sheet service.") { PR_STATIC_ASSERT(0 == AGENT_SHEET && 1 == USER_SHEET && 2 == AUTHOR_SHEET); NS_ASSERTION(!gInstance, "Someone is using CreateInstance instead of GetService"); gInstance = this; nsLayoutStatics::AddRef(); - - mReporter = new LayoutStyleSheetServiceReporter(); - NS_RegisterMemoryReporter(mReporter); } nsStyleSheetService::~nsStyleSheetService() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); gInstance = nullptr; nsLayoutStatics::Release(); } -NS_IMPL_ISUPPORTS1(nsStyleSheetService, nsIStyleSheetService) +NS_IMPL_ISUPPORTS_INHERITED1( + nsStyleSheetService, MemoryUniReporter, nsIStyleSheetService) void nsStyleSheetService::RegisterFromEnumerator(nsICategoryManager *aManager, const char *aCategory, nsISimpleEnumerator *aEnumerator, uint32_t aSheetType) { if (!aEnumerator) @@ -136,16 +118,18 @@ nsStyleSheetService::Init() RegisterFromEnumerator(catMan, "agent-style-sheets", sheets, AGENT_SHEET); catMan->EnumerateCategory("user-style-sheets", getter_AddRefs(sheets)); RegisterFromEnumerator(catMan, "user-style-sheets", sheets, USER_SHEET); catMan->EnumerateCategory("author-style-sheets", getter_AddRefs(sheets)); RegisterFromEnumerator(catMan, "author-style-sheets", sheets, AUTHOR_SHEET); + RegisterWeakMemoryReporter(this); + return NS_OK; } NS_IMETHODIMP nsStyleSheetService::LoadAndRegisterSheet(nsIURI *aSheetURI, uint32_t aSheetType) { nsresult rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType); @@ -296,18 +280,24 @@ nsStyleSheetService::GetInstance() static size_t SizeOfElementIncludingThis(nsIStyleSheet* aElement, MallocSizeOf aMallocSizeOf, void *aData) { return aElement->SizeOfIncludingThis(aMallocSizeOf); } +int64_t +nsStyleSheetService::Amount() +{ + return SizeOfIncludingThis(MallocSizeOf); +} + size_t -nsStyleSheetService::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const +nsStyleSheetService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { size_t n = aMallocSizeOf(this); n += mSheets[AGENT_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis, aMallocSizeOf); n += mSheets[USER_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis, aMallocSizeOf); n += mSheets[AUTHOR_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis, aMallocSizeOf);
--- a/layout/base/nsStyleSheetService.h +++ b/layout/base/nsStyleSheetService.h @@ -6,32 +6,35 @@ /* implementation of interface for managing user and user-agent style sheets */ #ifndef nsStyleSheetService_h_ #define nsStyleSheetService_h_ #include "nsCOMArray.h" #include "nsCOMPtr.h" +#include "nsIMemoryReporter.h" #include "nsIStyleSheetService.h" #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" class nsICategoryManager; class nsIMemoryReporter; class nsISimpleEnumerator; class nsIStyleSheet; #define NS_STYLESHEETSERVICE_CID \ {0xfcca6f83, 0x9f7d, 0x44e4, {0xa7, 0x4b, 0xb5, 0x94, 0x33, 0xe6, 0xc8, 0xc3}} #define NS_STYLESHEETSERVICE_CONTRACTID \ "@mozilla.org/content/style-sheet-service;1" -class nsStyleSheetService MOZ_FINAL : public nsIStyleSheetService +class nsStyleSheetService MOZ_FINAL + : public mozilla::MemoryUniReporter + , public nsIStyleSheetService { public: nsStyleSheetService() NS_HIDDEN; ~nsStyleSheetService() NS_HIDDEN; NS_DECL_ISUPPORTS NS_DECL_NSISTYLESHEETSERVICE @@ -41,29 +44,29 @@ class nsStyleSheetService MOZ_FINAL : pu nsCOMArray<nsIStyleSheet>* UserStyleSheets() { return &mSheets[USER_SHEET]; } nsCOMArray<nsIStyleSheet>* AuthorStyleSheets() { return &mSheets[AUTHOR_SHEET]; } size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; static nsStyleSheetService *GetInstance(); static nsStyleSheetService *gInstance; + int64_t Amount() MOZ_OVERRIDE; + private: NS_HIDDEN_(void) RegisterFromEnumerator(nsICategoryManager *aManager, const char *aCategory, nsISimpleEnumerator *aEnumerator, uint32_t aSheetType); NS_HIDDEN_(int32_t) FindSheetByURI(const nsCOMArray<nsIStyleSheet> &sheets, nsIURI *sheetURI); // Like LoadAndRegisterSheet, but doesn't notify. If successful, the // new sheet will be the last sheet in mSheets[aSheetType]. NS_HIDDEN_(nsresult) LoadAndRegisterSheetInternal(nsIURI *aSheetURI, uint32_t aSheetType); nsCOMArray<nsIStyleSheet> mSheets[3]; - - nsCOMPtr<nsIMemoryReporter> mReporter; }; #endif
--- a/layout/style/nsLayoutStylesheetCache.cpp +++ b/layout/style/nsLayoutStylesheetCache.cpp @@ -5,40 +5,24 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsLayoutStylesheetCache.h" #include "nsAppDirectoryServiceDefs.h" #include "mozilla/MemoryReporting.h" #include "mozilla/css/Loader.h" #include "nsIFile.h" -#include "nsIMemoryReporter.h" #include "nsNetUtil.h" #include "nsIObserverService.h" #include "nsServiceManagerUtils.h" #include "nsIXULRuntime.h" #include "nsCSSStyleSheet.h" -class LayoutStyleSheetCacheReporter MOZ_FINAL - : public mozilla::MemoryUniReporter -{ -public: - LayoutStyleSheetCacheReporter() - : MemoryUniReporter("explicit/layout/style-sheet-cache", - KIND_HEAP, UNITS_BYTES, - "Memory used for some built-in style sheets.") - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - return nsLayoutStylesheetCache::SizeOfIncludingThis(MallocSizeOf); - } -}; - -NS_IMPL_ISUPPORTS1(nsLayoutStylesheetCache, nsIObserver) +NS_IMPL_ISUPPORTS_INHERITED1( + nsLayoutStylesheetCache, MemoryUniReporter, nsIObserver) nsresult nsLayoutStylesheetCache::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData) { if (!strcmp(aTopic, "profile-before-change")) { mUserContentSheet = nullptr; @@ -153,27 +137,24 @@ nsLayoutStylesheetCache::FullScreenOverr void nsLayoutStylesheetCache::Shutdown() { NS_IF_RELEASE(gCSSLoader); NS_IF_RELEASE(gStyleCache); } -size_t -nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) +int64_t +nsLayoutStylesheetCache::Amount() { - return nsLayoutStylesheetCache::gStyleCache - ? nsLayoutStylesheetCache::gStyleCache-> - SizeOfIncludingThisHelper(aMallocSizeOf) - : 0; + return SizeOfIncludingThis(MallocSizeOf); } size_t -nsLayoutStylesheetCache::SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf) const +nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { size_t n = aMallocSizeOf(this); #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0; MEASURE(mScrollbarsSheet); MEASURE(mFormsSheet); MEASURE(mUserContentSheet); @@ -185,16 +166,19 @@ nsLayoutStylesheetCache::SizeOfIncluding // Measurement of the following members may be added later if DMD finds it is // worthwhile: // - gCSSLoader return n; } nsLayoutStylesheetCache::nsLayoutStylesheetCache() + : MemoryUniReporter("explicit/layout/style-sheet-cache", + KIND_HEAP, UNITS_BYTES, + "Memory used for some built-in style sheets.") { nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService(); NS_ASSERTION(obsSvc, "No global observer service?"); if (obsSvc) { obsSvc->AddObserver(this, "profile-before-change", false); obsSvc->AddObserver(this, "profile-do-change", false); @@ -219,36 +203,41 @@ nsLayoutStylesheetCache::nsLayoutStylesh } NS_ASSERTION(mQuirkSheet, "Could not load quirk.css"); NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/full-screen-override.css"); if (uri) { LoadSheet(uri, mFullScreenOverrideSheet, true); } NS_ASSERTION(mFullScreenOverrideSheet, "Could not load full-screen-override.css"); - - mReporter = new LayoutStyleSheetCacheReporter(); - NS_RegisterMemoryReporter(mReporter); } nsLayoutStylesheetCache::~nsLayoutStylesheetCache() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); gStyleCache = nullptr; } void +nsLayoutStylesheetCache::InitMemoryReporter() +{ + RegisterWeakMemoryReporter(this); +} + +void nsLayoutStylesheetCache::EnsureGlobal() { if (gStyleCache) return; gStyleCache = new nsLayoutStylesheetCache(); if (!gStyleCache) return; NS_ADDREF(gStyleCache); + + gStyleCache->InitMemoryReporter(); } void nsLayoutStylesheetCache::InitFromProfile() { nsCOMPtr<nsIXULRuntime> appInfo = do_GetService("@mozilla.org/xre/app-info;1"); if (appInfo) { bool inSafeMode = false;
--- a/layout/style/nsLayoutStylesheetCache.h +++ b/layout/style/nsLayoutStylesheetCache.h @@ -2,68 +2,67 @@ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsLayoutStylesheetCache_h__ #define nsLayoutStylesheetCache_h__ +#include "nsIMemoryReporter.h" #include "nsIObserver.h" #include "nsAutoPtr.h" #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" class nsCSSStyleSheet; class nsIFile; -class nsIMemoryReporter; class nsIURI; namespace mozilla { namespace css { class Loader; } } class nsLayoutStylesheetCache MOZ_FINAL - : public nsIObserver + : public mozilla::MemoryUniReporter + , public nsIObserver { NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER static nsCSSStyleSheet* ScrollbarsSheet(); static nsCSSStyleSheet* FormsSheet(); static nsCSSStyleSheet* UserContentSheet(); static nsCSSStyleSheet* UserChromeSheet(); static nsCSSStyleSheet* UASheet(); static nsCSSStyleSheet* QuirkSheet(); static nsCSSStyleSheet* FullScreenOverrideSheet(); static void Shutdown(); - static size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); + int64_t Amount() MOZ_OVERRIDE; + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; private: nsLayoutStylesheetCache(); ~nsLayoutStylesheetCache(); static void EnsureGlobal(); void InitFromProfile(); + void InitMemoryReporter(); static void LoadSheetFile(nsIFile* aFile, nsRefPtr<nsCSSStyleSheet> &aSheet); static void LoadSheet(nsIURI* aURI, nsRefPtr<nsCSSStyleSheet> &aSheet, bool aEnableUnsafeRules); - size_t SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf) const; - static nsLayoutStylesheetCache* gStyleCache; static mozilla::css::Loader* gCSSLoader; nsRefPtr<nsCSSStyleSheet> mScrollbarsSheet; nsRefPtr<nsCSSStyleSheet> mFormsSheet; nsRefPtr<nsCSSStyleSheet> mUserContentSheet; nsRefPtr<nsCSSStyleSheet> mUserChromeSheet; nsRefPtr<nsCSSStyleSheet> mUASheet; nsRefPtr<nsCSSStyleSheet> mQuirkSheet; nsRefPtr<nsCSSStyleSheet> mFullScreenOverrideSheet; - - nsCOMPtr<nsIMemoryReporter> mReporter; }; #endif
--- a/modules/libpref/src/Preferences.cpp +++ b/modules/libpref/src/Preferences.cpp @@ -336,17 +336,17 @@ PreferenceServiceReporter::CollectReport return NS_OK; } namespace { class AddPreferencesMemoryReporterRunnable : public nsRunnable { NS_IMETHOD Run() { - return NS_RegisterMemoryReporter(new PreferenceServiceReporter()); + return RegisterStrongMemoryReporter(new PreferenceServiceReporter()); } }; } // anonymous namespace // static Preferences* Preferences::GetInstanceForService() { @@ -371,19 +371,19 @@ Preferences::GetInstanceForService() return nullptr; } gCacheData = new nsTArray<nsAutoPtr<CacheData> >(); gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>(); // Preferences::GetInstanceForService() can be called from GetService(), and - // NS_RegisterMemoryReporter calls GetService(nsIMemoryReporter). To avoid a - // potential recursive GetService() call, we can't register the memory - // reporter here; instead, do it off a runnable. + // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To + // avoid a potential recursive GetService() call, we can't register the + // memory reporter here; instead, do it off a runnable. nsRefPtr<AddPreferencesMemoryReporterRunnable> runnable = new AddPreferencesMemoryReporterRunnable(); NS_DispatchToMainThread(runnable); NS_ADDREF(sPreferences); return sPreferences; }
--- a/netwerk/cache/nsDiskCacheDevice.cpp +++ b/netwerk/cache/nsDiskCacheDevice.cpp @@ -394,22 +394,22 @@ private: nsDiskCacheDevice::nsDiskCacheDevice() : mCacheCapacity(0) , mMaxEntrySize(-1) // -1 means "no limit" , mInitialized(false) , mClearingDiskCache(false) , mReporter(nullptr) { mReporter = new NetworkDiskCacheReporter(this); - NS_RegisterMemoryReporter(mReporter); + RegisterWeakMemoryReporter(mReporter); } nsDiskCacheDevice::~nsDiskCacheDevice() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(mReporter); Shutdown(); } /** * methods of nsCacheDevice */ nsresult
--- a/netwerk/cache/nsMemoryCacheDevice.cpp +++ b/netwerk/cache/nsMemoryCacheDevice.cpp @@ -59,23 +59,23 @@ nsMemoryCacheDevice::nsMemoryCacheDevice mMaxEntryCount(0), mMaxEntrySize(-1), // -1 means "no limit" mReporter(nullptr) { for (int i=0; i<kQueueCount; ++i) PR_INIT_CLIST(&mEvictionList[i]); mReporter = new NetworkMemoryCacheReporter(this); - NS_RegisterMemoryReporter(mReporter); + mozilla::RegisterWeakMemoryReporter(mReporter); } nsMemoryCacheDevice::~nsMemoryCacheDevice() { - NS_UnregisterMemoryReporter(mReporter); + mozilla::UnregisterWeakMemoryReporter(mReporter); Shutdown(); } nsresult nsMemoryCacheDevice::Init() { if (mInitialized) return NS_ERROR_ALREADY_INITIALIZED;
--- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -2,17 +2,16 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsDNSService2.h" #include "nsIDNSRecord.h" #include "nsIDNSListener.h" #include "nsICancelable.h" -#include "nsIMemoryReporter.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "nsIServiceManager.h" #include "nsIXPConnect.h" #include "nsProxyRelease.h" #include "nsReadableUtils.h" #include "nsString.h" #include "nsAutoPtr.h" @@ -389,46 +388,32 @@ nsDNSSyncRequest::SizeOfIncludingThis(Ma // is worthwhile: // - mMonitor return n; } //----------------------------------------------------------------------------- -class NetworkDNSServiceReporter MOZ_FINAL : public MemoryUniReporter -{ -public: - NetworkDNSServiceReporter(nsDNSService* aService) - : MemoryUniReporter("explicit/network/dns-service", - KIND_HEAP, UNITS_BYTES, - "Memory used for the DNS service.") - , mService(aService) - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - return mService->SizeOfIncludingThis(MallocSizeOf); - } - - nsDNSService *mService; -}; - nsDNSService::nsDNSService() - : mLock("nsDNSServer.mLock") + : MemoryUniReporter("explicit/network/dns-service", + KIND_HEAP, UNITS_BYTES, + "Memory used for the DNS service.") + , mLock("nsDNSServer.mLock") , mFirstTime(true) , mOffline(false) { } nsDNSService::~nsDNSService() { } -NS_IMPL_ISUPPORTS3(nsDNSService, nsIDNSService, nsPIDNSService, nsIObserver) +NS_IMPL_ISUPPORTS_INHERITED3(nsDNSService, MemoryUniReporter, nsIDNSService, + nsPIDNSService, nsIObserver) NS_IMETHODIMP nsDNSService::Init() { if (mResolver) return NS_OK; NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED); @@ -524,26 +509,25 @@ nsDNSService::Init() while (tokenizer.hasMoreTokens()) { const nsSubstring& domain = tokenizer.nextToken(); mLocalDomains.PutEntry(nsDependentCString(NS_ConvertUTF16toUTF8(domain).get())); } } } - mReporter = new NetworkDNSServiceReporter(this); - NS_RegisterMemoryReporter(mReporter); + RegisterWeakMemoryReporter(this); return rv; } NS_IMETHODIMP nsDNSService::Shutdown() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); nsRefPtr<nsHostResolver> res; { MutexAutoLock lock(mLock); res = mResolver; mResolver = nullptr; } if (res) @@ -932,17 +916,17 @@ nsDNSService::GetDNSCacheEntries(nsTArra static size_t SizeOfLocalDomainsEntryExcludingThis(nsCStringHashKey* entry, MallocSizeOf mallocSizeOf, void*) { return entry->GetKey().SizeOfExcludingThisMustBeUnshared(mallocSizeOf); } size_t -nsDNSService::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const +nsDNSService::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { // Measurement of the following members may be added later if DMD finds it // is worthwhile: // - mIDN // - mLock size_t n = mallocSizeOf(this); n += mResolver->SizeOfIncludingThis(mallocSizeOf);
--- a/netwerk/dns/nsDNSService2.h +++ b/netwerk/dns/nsDNSService2.h @@ -2,39 +2,43 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsDNSService2_h__ #define nsDNSService2_h__ #include "nsPIDNSService.h" #include "nsIIDNService.h" +#include "nsIMemoryReporter.h" #include "nsIObserver.h" #include "nsHostResolver.h" #include "nsAutoPtr.h" #include "nsString.h" #include "nsTHashtable.h" #include "nsHashKeys.h" #include "mozilla/Mutex.h" #include "mozilla/Attributes.h" -class nsIMemoryReporter; - -class nsDNSService MOZ_FINAL : public nsPIDNSService +class nsDNSService MOZ_FINAL : public mozilla::MemoryUniReporter + , public nsPIDNSService , public nsIObserver { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSPIDNSSERVICE NS_DECL_NSIDNSSERVICE NS_DECL_NSIOBSERVER nsDNSService(); ~nsDNSService(); + int64_t Amount() MOZ_OVERRIDE + { + return SizeOfIncludingThis(MallocSizeOf); + } size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; private: uint16_t GetAFForLookup(const nsACString &host, uint32_t flags); nsRefPtr<nsHostResolver> mResolver; nsCOMPtr<nsIIDNService> mIDN; @@ -45,13 +49,11 @@ private: // IPv4 DNS lookups are performed. This allows the user to disable IPv6 on // a per-domain basis and work around broken DNS servers. See bug 68796. nsAdoptingCString mIPv4OnlyDomains; bool mDisableIPv6; bool mDisablePrefetch; bool mFirstTime; bool mOffline; nsTHashtable<nsCStringHashKey> mLocalDomains; - - nsCOMPtr<nsIMemoryReporter> mReporter; }; #endif //nsDNSService2_h__
--- a/netwerk/dns/nsEffectiveTLDService.cpp +++ b/netwerk/dns/nsEffectiveTLDService.cpp @@ -8,23 +8,23 @@ // complete description of the expected file format and parsing rules, see // http://wiki.mozilla.org/Gecko:Effective_TLD_Service #include "mozilla/MemoryReporting.h" #include "mozilla/Util.h" #include "nsEffectiveTLDService.h" #include "nsIIDNService.h" -#include "nsIMemoryReporter.h" #include "nsNetUtil.h" #include "prnetdb.h" using namespace mozilla; -NS_IMPL_ISUPPORTS1(nsEffectiveTLDService, nsIEffectiveTLDService) +NS_IMPL_ISUPPORTS_INHERITED1(nsEffectiveTLDService, MemoryUniReporter, + nsIEffectiveTLDService) // ---------------------------------------------------------------------- #define ETLD_STR_NUM_1(line) str##line #define ETLD_STR_NUM(line) ETLD_STR_NUM_1(line) #define ETLD_ENTRY_OFFSET(name) offsetof(struct etld_string_list, ETLD_STR_NUM(__LINE__)) const ETLDEntry nsDomainEntry::entries[] = { @@ -56,38 +56,25 @@ nsDomainEntry::FuncForStaticAsserts(void #undef ETLD_ENTRY_OFFSET #undef ETLD_STR_NUM #undef ETLD_STR_NUM1 // ---------------------------------------------------------------------- static nsEffectiveTLDService *gService = nullptr; -class EffectiveTLDServiceReporter MOZ_FINAL : public MemoryUniReporter -{ -public: - EffectiveTLDServiceReporter() - : MemoryUniReporter("explicit/xpcom/effective-TLD-service", - KIND_HEAP, UNITS_BYTES, - "Memory used by the effective TLD service.") - {} - -private: - int64_t Amount() MOZ_OVERRIDE - { - return gService ? gService->SizeOfIncludingThis(MallocSizeOf) : 0; - } -}; - nsEffectiveTLDService::nsEffectiveTLDService() // We'll probably have to rehash at least once, since nsTHashtable doesn't // use a perfect hash, but at least we'll save a few rehashes along the way. // Next optimization here is to precompute the hash using something like // gperf, but one step at a time. :-) - : mHash(ArrayLength(nsDomainEntry::entries)) + : MemoryUniReporter("explicit/xpcom/effective-TLD-service", + KIND_HEAP, UNITS_BYTES, + "Memory used by the effective TLD service.") + , mHash(ArrayLength(nsDomainEntry::entries)) { } nsresult nsEffectiveTLDService::Init() { const ETLDEntry *entries = nsDomainEntry::entries; @@ -107,37 +94,41 @@ nsEffectiveTLDService::Init() #endif nsDomainEntry *entry = mHash.PutEntry(domain); NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); entry->SetData(&entries[i]); } MOZ_ASSERT(!gService); gService = this; - mReporter = new EffectiveTLDServiceReporter(); - NS_RegisterMemoryReporter(mReporter); + RegisterWeakMemoryReporter(this); return NS_OK; } nsEffectiveTLDService::~nsEffectiveTLDService() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); gService = nullptr; } +int64_t +nsEffectiveTLDService::Amount() +{ + return SizeOfIncludingThis(MallocSizeOf); +} + size_t -nsEffectiveTLDService::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) +nsEffectiveTLDService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { size_t n = aMallocSizeOf(this); n += mHash.SizeOfExcludingThis(nullptr, aMallocSizeOf); // Measurement of the following members may be added later if DMD finds it is // worthwhile: - // - mReporter // - mIDNService return n; } // External function for dealing with URI's correctly. // Pulls out the host portion from an nsIURI, and calls through to // GetPublicSuffixFromHost().
--- a/netwerk/dns/nsEffectiveTLDService.h +++ b/netwerk/dns/nsEffectiveTLDService.h @@ -97,28 +97,30 @@ private: char strtab[1]; } strings; static const ETLDEntry entries[]; void FuncForStaticAsserts(void); #undef ETLD_STR_NUM #undef ETLD_STR_NUM1 }; -class nsEffectiveTLDService MOZ_FINAL : public nsIEffectiveTLDService +class nsEffectiveTLDService MOZ_FINAL + : public mozilla::MemoryUniReporter + , public nsIEffectiveTLDService { public: NS_DECL_ISUPPORTS NS_DECL_NSIEFFECTIVETLDSERVICE nsEffectiveTLDService(); nsresult Init(); + int64_t Amount() MOZ_OVERRIDE; size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); private: nsresult GetBaseDomainInternal(nsCString &aHostname, int32_t aAdditionalParts, nsACString &aBaseDomain); nsresult NormalizeHostname(nsCString &aHostname); ~nsEffectiveTLDService(); - nsCOMPtr<nsIMemoryReporter> mReporter; nsTHashtable<nsDomainEntry> mHash; nsCOMPtr<nsIIDNService> mIDNService; };
--- a/startupcache/StartupCache.cpp +++ b/startupcache/StartupCache.cpp @@ -11,17 +11,16 @@ #include "mozilla/scache/StartupCache.h" #include "nsAutoPtr.h" #include "nsClassHashtable.h" #include "nsComponentManagerUtils.h" #include "nsDirectoryServiceUtils.h" #include "nsIClassInfo.h" #include "nsIFile.h" -#include "nsIMemoryReporter.h" #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsIOutputStream.h" #include "nsIStartupCache.h" #include "nsIStorageStream.h" #include "nsIStreamBufferAccess.h" #include "nsIStringStream.h" #include "nsISupports.h" @@ -47,48 +46,41 @@ #define SC_WORDSIZE "4" #else #define SC_WORDSIZE "8" #endif namespace mozilla { namespace scache { -class StartupCacheMappingReporter MOZ_FINAL : public MemoryUniReporter +NS_IMETHODIMP +StartupCache::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData) { -public: - StartupCacheMappingReporter() - : MemoryUniReporter("explicit/startup-cache/mapping", - KIND_NONHEAP, UNITS_BYTES, -"Memory used to hold the mapping of the startup cache from file. This memory " -"is likely to be swapped out shortly after start-up.") - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - mozilla::scache::StartupCache* sc = - mozilla::scache::StartupCache::GetSingleton(); - return sc ? sc->SizeOfMapping() : 0; - } -}; +#define REPORT(_path, _kind, _amount, _desc) \ + do { \ + nsresult rv = \ + aHandleReport->Callback(EmptyCString(), \ + NS_LITERAL_CSTRING(_path), \ + _kind, UNITS_BYTES, _amount, \ + NS_LITERAL_CSTRING(_desc), aData); \ + NS_ENSURE_SUCCESS(rv, rv); \ + } while (0) -class StartupCacheDataReporter MOZ_FINAL : public MemoryUniReporter -{ -public: - StartupCacheDataReporter() - : MemoryUniReporter("explicit/startup-cache/data", KIND_HEAP, UNITS_BYTES, -"Memory used by the startup cache for things other than the file mapping.") - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - mozilla::scache::StartupCache* sc = - mozilla::scache::StartupCache::GetSingleton(); - return sc ? sc->HeapSizeOfIncludingThis(MallocSizeOf) : 0; - } + REPORT("explicit/startup-cache/mapping", KIND_NONHEAP, + SizeOfMapping(), + "Memory used to hold the mapping of the startup cache from file. " + "This memory is likely to be swapped out shortly after start-up."); + + REPORT("explicit/startup-cache/data", KIND_HEAP, + HeapSizeOfIncludingThis(MallocSizeOf), + "Memory used by the startup cache for things other than the file " + "mapping."); + + return NS_OK; }; static const char sStartupCacheName[] = "startupCache." SC_WORDSIZE "." SC_ENDIAN; #if defined(XP_WIN) && defined(MOZ_METRO) static const char sMetroStartupCacheName[] = "metroStartupCache." SC_WORDSIZE "." SC_ENDIAN; #endif static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID); @@ -126,20 +118,21 @@ StartupCache::InitSingleton() return rv; } StaticRefPtr<StartupCache> StartupCache::gStartupCache; bool StartupCache::gShutdownInitiated; bool StartupCache::gIgnoreDiskCache; enum StartupCache::TelemetrifyAge StartupCache::gPostFlushAgeAction = StartupCache::IGNORE_AGE; -NS_IMPL_ISUPPORTS1(StartupCache, nsISupports) +NS_IMPL_ISUPPORTS_INHERITED0(StartupCache, MemoryMultiReporter) StartupCache::StartupCache() - : mArchive(nullptr), mStartupWriteInitiated(false), mWriteThread(nullptr) + : MemoryMultiReporter("startup-cache"), + mArchive(nullptr), mStartupWriteInitiated(false), mWriteThread(nullptr) { } StartupCache::~StartupCache() { if (mTimer) { mTimer->Cancel(); } @@ -151,18 +144,17 @@ StartupCache::~StartupCache() // If we shutdown quickly timer wont have fired. Instead of writing // it on the main thread and block the shutdown we simply wont update // the startup cache. Always do this if the file doesn't exist since // we use it part of the packge step. if (!mArchive) { WriteToDisk(); } - NS_UnregisterMemoryReporter(mMappingReporter); - NS_UnregisterMemoryReporter(mDataReporter); + UnregisterWeakMemoryReporter(this); } nsresult StartupCache::Init() { // workaround for bug 653936 nsCOMPtr<nsIProtocolHandler> jarInitializer(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar")); @@ -239,20 +231,17 @@ StartupCache::Init() // Sometimes we don't have a cache yet, that's ok. // If it's corrupted, just remove it and start over. if (gIgnoreDiskCache || (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)) { NS_WARNING("Failed to load startupcache file correctly, removing!"); InvalidateCache(); } - mMappingReporter = new StartupCacheMappingReporter(); - mDataReporter = new StartupCacheDataReporter(); - NS_RegisterMemoryReporter(mMappingReporter); - NS_RegisterMemoryReporter(mDataReporter); + RegisterWeakMemoryReporter(this); return NS_OK; } /** * LoadArchive can be called from the main thread or while reloading cache on write thread. */ nsresult @@ -380,17 +369,17 @@ StartupCache::PutBuffer(const char* id, #endif entry = new CacheEntry(data.forget(), len); mTable.Put(idStr, entry); return ResetStartupWriteTimer(); } size_t -StartupCache::SizeOfMapping() +StartupCache::SizeOfMapping() { return mArchive ? mArchive->SizeOfMapping() : 0; } size_t StartupCache::HeapSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { // This function could measure more members, but they haven't been found by
--- a/startupcache/StartupCache.h +++ b/startupcache/StartupCache.h @@ -6,26 +6,25 @@ #ifndef StartupCache_h_ #define StartupCache_h_ #include "nsClassHashtable.h" #include "nsComponentManagerUtils.h" #include "nsZipArchive.h" #include "nsIStartupCache.h" #include "nsITimer.h" +#include "nsIMemoryReporter.h" #include "nsIObserverService.h" #include "nsIObserver.h" #include "nsIOutputStream.h" #include "nsIFile.h" #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" #include "mozilla/StaticPtr.h" -class nsIMemoryReporter; - /** * The StartupCache is a persistent cache of simple key-value pairs, * where the keys are null-terminated c-strings and the values are * arbitrary data, passed as a (char*, size) tuple. * * Clients should use the GetSingleton() static method to access the cache. It * will be available from the end of XPCOM init (NS_InitXPCOM3 in nsXPComInit.cpp), * until XPCOM shutdown begins. The GetSingleton() method will return null if the cache @@ -93,17 +92,17 @@ struct CacheEntry // We don't want to refcount StartupCache, and ObserverService wants to // refcount its listeners, so we'll let it refcount this instead. class StartupCacheListener MOZ_FINAL : public nsIObserver { NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIOBSERVER }; -class StartupCache : public nsISupports +class StartupCache : public mozilla::MemoryMultiReporter { friend class StartupCacheListener; friend class StartupCacheWrapper; public: NS_DECL_ISUPPORTS @@ -126,16 +125,19 @@ public: nsresult GetDebugObjectOutputStream(nsIObjectOutputStream* aStream, nsIObjectOutputStream** outStream); nsresult RecordAgesAlways(); static StartupCache* GetSingleton(); static void DeleteSingleton(); + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData); + // This measures all the heap memory used by the StartupCache, i.e. it // excludes the mapping. size_t HeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); size_t SizeOfMapping(); private: StartupCache(); @@ -174,19 +176,16 @@ private: static StaticRefPtr<StartupCache> gStartupCache; static bool gShutdownInitiated; static bool gIgnoreDiskCache; PRThread *mWriteThread; #ifdef DEBUG nsTHashtable<nsISupportsHashKey> mWriteObjectMap; #endif - - nsCOMPtr<nsIMemoryReporter> mMappingReporter; - nsCOMPtr<nsIMemoryReporter> mDataReporter; }; // This debug outputstream attempts to detect if clients are writing multiple // references to the same object. We only support that if that object // is a singleton. #ifdef DEBUG class StartupCacheDebugOutputStream MOZ_FINAL : public nsIObjectOutputStream
--- a/storage/src/mozStorageService.cpp +++ b/storage/src/mozStorageService.cpp @@ -28,17 +28,16 @@ #include "sqlite3.h" #ifdef SQLITE_OS_WIN // "windows.h" was included and it can #define lots of things we care about... #undef CompareString #endif #include "nsIPromptService.h" -#include "nsIMemoryReporter.h" #ifdef MOZ_STORAGE_MEMORY # include "mozmemory.h" # ifdef MOZ_DMD # include "DMD.h" # endif #endif @@ -65,166 +64,150 @@ static mozilla::Atomic<size_t> gSqliteMe #endif static int64_t StorageSQLiteDistinguishedAmount() { return ::sqlite3_memory_used(); } -class StorageSQLiteReporter MOZ_FINAL : public MemoryMultiReporter +/** + * Passes a single SQLite memory statistic to a memory reporter callback. + * + * @param aHandleReport + * The callback. + * @param aData + * The data for the callback. + * @param aConn + * The SQLite connection. + * @param aPathHead + * Head of the path for the memory report. + * @param aKind + * The memory report statistic kind, one of "stmt", "cache" or + * "schema". + * @param aDesc + * The memory report description. + * @param aOption + * The SQLite constant for getting the measurement. + * @param aTotal + * The accumulator for the measurement. + */ +nsresult +ReportConn(nsIHandleReportCallback *aHandleReport, + nsISupports *aData, + sqlite3 *aConn, + const nsACString &aPathHead, + const nsACString &aKind, + const nsACString &aDesc, + int aOption, + size_t *aTotal) { -private: - Service *mService; // a weakref because Service contains a strongref to this - nsCString mStmtDesc; - nsCString mCacheDesc; - nsCString mSchemaDesc; + nsCString path(aPathHead); + path.Append(aKind); + path.AppendLiteral("-used"); + + int curr = 0, max = 0; + int rc = ::sqlite3_db_status(aConn, aOption, &curr, &max, 0); + nsresult rv = convertResultCode(rc); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aHandleReport->Callback(EmptyCString(), path, + nsIMemoryReporter::KIND_HEAP, + nsIMemoryReporter::UNITS_BYTES, int64_t(curr), + aDesc, aData); + NS_ENSURE_SUCCESS(rv, rv); + *aTotal += curr; + + return NS_OK; +} -public: - StorageSQLiteReporter(Service *aService) - : MemoryMultiReporter("storage-sqlite") - , mService(aService) +// Warning: To get a Connection's measurements requires holding its lock. +// There may be a delay getting the lock if another thread is accessing the +// Connection. This isn't very nice if CollectReports is called from the main +// thread! But at the time of writing this function is only called when +// about:memory is loaded (not, for example, when telemetry pings occur) and +// any delays in that case aren't so bad. +NS_IMETHODIMP +Service::CollectReports(nsIHandleReportCallback *aHandleReport, + nsISupports *aData) +{ + nsresult rv; + size_t totalConnSize = 0; { - mStmtDesc = NS_LITERAL_CSTRING( - "Memory (approximate) used by all prepared statements used by " - "connections to this database."); + nsTArray<nsRefPtr<Connection> > connections; + getConnections(connections); + + for (uint32_t i = 0; i < connections.Length(); i++) { + nsRefPtr<Connection> &conn = connections[i]; + + // Someone may have closed the Connection, in which case we skip it. + bool isReady; + (void)conn->GetConnectionReady(&isReady); + if (!isReady) { + continue; + } + + nsCString pathHead("explicit/storage/sqlite/"); + pathHead.Append(conn->getFilename()); + pathHead.AppendLiteral("/"); + + SQLiteMutexAutoLock lockedScope(conn->sharedDBMutex); - mCacheDesc = NS_LITERAL_CSTRING( - "Memory (approximate) used by all pager caches used by connections " - "to this database."); + NS_NAMED_LITERAL_CSTRING(stmtDesc, + "Memory (approximate) used by all prepared statements used by " + "connections to this database."); + rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead, + NS_LITERAL_CSTRING("stmt"), stmtDesc, + SQLITE_DBSTATUS_STMT_USED, &totalConnSize); + NS_ENSURE_SUCCESS(rv, rv); + + NS_NAMED_LITERAL_CSTRING(cacheDesc, + "Memory (approximate) used by all pager caches used by connections " + "to this database."); + rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead, + NS_LITERAL_CSTRING("cache"), cacheDesc, + SQLITE_DBSTATUS_CACHE_USED, &totalConnSize); + NS_ENSURE_SUCCESS(rv, rv); - mSchemaDesc = NS_LITERAL_CSTRING( - "Memory (approximate) used to store the schema for all databases " - "associated with connections to this database."); + NS_NAMED_LITERAL_CSTRING(schemaDesc, + "Memory (approximate) used to store the schema for all databases " + "associated with connections to this database."); + rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead, + NS_LITERAL_CSTRING("schema"), schemaDesc, + SQLITE_DBSTATUS_SCHEMA_USED, &totalConnSize); + NS_ENSURE_SUCCESS(rv, rv); + } + +#ifdef MOZ_DMD + if (::sqlite3_memory_used() != int64_t(gSqliteMemoryUsed)) { + NS_WARNING("memory consumption reported by SQLite doesn't match " + "our measurements"); + } +#endif } - // Warning: To get a Connection's measurements requires holding its lock. - // There may be a delay getting the lock if another thread is accessing the - // Connection. This isn't very nice if CollectReports is called from the - // main thread! But at the time of writing this function is only called when - // about:memory is loaded (not, for example, when telemetry pings occur) and - // any delays in that case aren't so bad. - NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb, - nsISupports *aClosure) - { - nsresult rv; - size_t totalConnSize = 0; - { - nsTArray<nsRefPtr<Connection> > connections; - mService->getConnections(connections); - - for (uint32_t i = 0; i < connections.Length(); i++) { - nsRefPtr<Connection> &conn = connections[i]; - - // Someone may have closed the Connection, in which case we skip it. - bool isReady; - (void)conn->GetConnectionReady(&isReady); - if (!isReady) { - continue; - } - - nsCString pathHead("explicit/storage/sqlite/"); - pathHead.Append(conn->getFilename()); - pathHead.AppendLiteral("/"); - - SQLiteMutexAutoLock lockedScope(conn->sharedDBMutex); - - rv = reportConn(aCb, aClosure, *conn.get(), pathHead, - NS_LITERAL_CSTRING("stmt"), mStmtDesc, - SQLITE_DBSTATUS_STMT_USED, &totalConnSize); - NS_ENSURE_SUCCESS(rv, rv); - - rv = reportConn(aCb, aClosure, *conn.get(), pathHead, - NS_LITERAL_CSTRING("cache"), mCacheDesc, - SQLITE_DBSTATUS_CACHE_USED, &totalConnSize); - NS_ENSURE_SUCCESS(rv, rv); - - rv = reportConn(aCb, aClosure, *conn.get(), pathHead, - NS_LITERAL_CSTRING("schema"), mSchemaDesc, - SQLITE_DBSTATUS_SCHEMA_USED, &totalConnSize); - NS_ENSURE_SUCCESS(rv, rv); - } - -#ifdef MOZ_DMD - if (::sqlite3_memory_used() != int64_t(gSqliteMemoryUsed)) { - NS_WARNING("memory consumption reported by SQLite doesn't match " - "our measurements"); - } -#endif - } - - int64_t other = ::sqlite3_memory_used() - totalConnSize; + int64_t other = ::sqlite3_memory_used() - totalConnSize; - rv = aCb->Callback(NS_LITERAL_CSTRING(""), - NS_LITERAL_CSTRING("explicit/storage/sqlite/other"), - nsIMemoryReporter::KIND_HEAP, - nsIMemoryReporter::UNITS_BYTES, other, - NS_LITERAL_CSTRING("All unclassified sqlite memory."), - aClosure); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; - } + rv = aHandleReport->Callback( + EmptyCString(), + NS_LITERAL_CSTRING("explicit/storage/sqlite/other"), + KIND_HEAP, UNITS_BYTES, other, + NS_LITERAL_CSTRING("All unclassified sqlite memory."), + aData); + NS_ENSURE_SUCCESS(rv, rv); -private: - /** - * Passes a single SQLite memory statistic to a memory reporter callback. - * - * @param aCallback - * The callback. - * @param aClosure - * The closure for the callback. - * @param aConn - * The SQLite connection. - * @param aPathHead - * Head of the path for the memory report. - * @param aKind - * The memory report statistic kind, one of "stmt", "cache" or - * "schema". - * @param aDesc - * The memory report description. - * @param aOption - * The SQLite constant for getting the measurement. - * @param aTotal - * The accumulator for the measurement. - */ - nsresult reportConn(nsIMemoryReporterCallback *aCb, - nsISupports *aClosure, - sqlite3 *aConn, - const nsACString &aPathHead, - const nsACString &aKind, - const nsACString &aDesc, - int aOption, - size_t *aTotal) - { - nsCString path(aPathHead); - path.Append(aKind); - path.AppendLiteral("-used"); - - int curr = 0, max = 0; - int rc = ::sqlite3_db_status(aConn, aOption, &curr, &max, 0); - nsresult rv = convertResultCode(rc); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aCb->Callback(NS_LITERAL_CSTRING(""), path, - nsIMemoryReporter::KIND_HEAP, - nsIMemoryReporter::UNITS_BYTES, int64_t(curr), - aDesc, aClosure); - NS_ENSURE_SUCCESS(rv, rv); - *aTotal += curr; - - return NS_OK; - } -}; + return NS_OK; +} //////////////////////////////////////////////////////////////////////////////// //// Service -NS_IMPL_ISUPPORTS2( +NS_IMPL_ISUPPORTS_INHERITED2( Service, + MemoryMultiReporter, mozIStorageService, nsIObserver ) Service *Service::gService = nullptr; Service * Service::getSingleton() @@ -290,26 +273,27 @@ int32_t Service::getSynchronousPref() { return sSynchronousPref; } int32_t Service::sDefaultPageSize = PREF_TS_PAGESIZE_DEFAULT; Service::Service() -: mMutex("Service::mMutex") +: MemoryMultiReporter("storage-sqlite") +, mMutex("Service::mMutex") , mSqliteVFS(nullptr) , mRegistrationMutex("Service::mRegistrationMutex") , mConnections() { } Service::~Service() { - (void)::NS_UnregisterMemoryReporter(mStorageSQLiteReporter); + mozilla::UnregisterWeakMemoryReporter(this); mozilla::UnregisterStorageSQLiteDistinguishedAmount(); int rc = sqlite3_vfs_unregister(mSqliteVFS); if (rc != SQLITE_OK) NS_WARNING("Failed to unregister sqlite vfs wrapper."); // Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but // there is nothing actionable we can do in that case. @@ -530,21 +514,17 @@ Service::initialize() Preferences::GetInt(PREF_TS_SYNCHRONOUS, PREF_TS_SYNCHRONOUS_DEFAULT); // We need to obtain the toolkit.storage.pageSize preferences on the main // thread because the preference service can only be accessed there. This // is cached in the service for all future Open[Unshared]Database calls. sDefaultPageSize = Preferences::GetInt(PREF_TS_PAGESIZE, PREF_TS_PAGESIZE_DEFAULT); - // Create and register our SQLite memory reporter and distinguished amount - // function. Registration can only happen on the main thread (otherwise - // you'll get cryptic crashes). - mStorageSQLiteReporter = new StorageSQLiteReporter(this); - (void)::NS_RegisterMemoryReporter(mStorageSQLiteReporter); + mozilla::RegisterWeakMemoryReporter(this); mozilla::RegisterStorageSQLiteDistinguishedAmount(StorageSQLiteDistinguishedAmount); return NS_OK; } int Service::localeCompareStrings(const nsAString &aStr1, const nsAString &aStr2,
--- a/storage/src/mozStorageService.h +++ b/storage/src/mozStorageService.h @@ -5,31 +5,33 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MOZSTORAGESERVICE_H #define MOZSTORAGESERVICE_H #include "nsCOMPtr.h" #include "nsICollation.h" #include "nsIFile.h" +#include "nsIMemoryReporter.h" #include "nsIObserver.h" #include "nsTArray.h" #include "mozilla/Mutex.h" #include "mozIStorageService.h" class nsIMemoryReporter; class nsIXPConnect; struct sqlite3_vfs; namespace mozilla { namespace storage { class Connection; -class Service : public mozIStorageService +class Service : public MemoryMultiReporter + , public mozIStorageService , public nsIObserver { public: /** * Initializes the service. This must be called before any other function! */ nsresult initialize(); @@ -51,16 +53,19 @@ public: int32_t aComparisonStrength); static Service *getSingleton(); NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_MOZISTORAGESERVICE NS_DECL_NSIOBSERVER + NS_IMETHOD CollectReports(nsIHandleReportCallback *aHandleReport, + nsISupports *aData); + /** * Obtains an already AddRefed pointer to XPConnect. This is used by * language helpers. */ static already_AddRefed<nsIXPConnect> getXPConnect(); /** * Obtains the cached data for the toolkit.storage.synchronous preference.
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul @@ -1,17 +1,17 @@ <?xml version="1.0"?> <?xml-stylesheet type="text/css" href="chrome://global/skin"?> <?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> <window title="about:memory" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> - <!-- This file uses fake memory reporters to test the presentation of memory + <!-- This file uses fake memory reporters to test the presentation of memory reports in about:memory. test_memoryReporters.xul uses the real memory reporters to test whether the memory reporters are producing sensible results. --> <!-- test results are displayed in the html:body --> <body xmlns="http://www.w3.org/1999/xhtml"></body> <!-- test code goes here --> @@ -22,25 +22,18 @@ SimpleTest.expectAssertions(27); const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); - // Remove all the real reporters; save them to restore at the end. - mgr.blockRegistration(); - let e = mgr.enumerateReporters(); - let realReporters = []; - while (e.hasMoreElements()) { - let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter); - mgr.unregisterReporter(r); - realReporters.push(r); - } + // Hide all the real reporters; we'll restore them at the end. + mgr.blockRegistrationAndHideExistingReporters(); // Setup various fake-but-deterministic reporters. const KB = 1024; const MB = KB * KB; const NONHEAP = Ci.nsIMemoryReporter.KIND_NONHEAP; const HEAP = Ci.nsIMemoryReporter.KIND_HEAP; const OTHER = Ci.nsIMemoryReporter.KIND_OTHER; @@ -118,34 +111,34 @@ aCbObj.callback("", aP, OTHER, COUNT, 1, "Desc.", aClosure); } f("compartments/user/bar"); f("compartments/system/bar"); } } ]; for (let i = 0; i < fakeReporters.length; i++) { - mgr.registerReporterEvenIfBlocked(fakeReporters[i]); + mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]); } // mgr.explicit sums "heap-allocated" and all the appropriate NONHEAP ones: // - "explicit/c", "explicit/cc" x 2, "explicit/d", "explicit/e" // - but *not* "explicit/c/d" x 2 // Check explicit now before we add the fake reporters for the fake 2nd // and subsequent processes. // // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a // --enable-trace-malloc build. Allow for that exception, but *only* that // exception. try { is(mgr.explicit, 500*MB + (100 + 13 + 10)*MB + 599*KB, "mgr.explicit"); } catch (ex) { is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception"); } - + // The main process always comes first when we display about:memory. The // remaining processes are sorted by their |resident| values (starting with // the largest). Processes without a |resident| memory reporter are saved // for the end. let fakeReporters2 = [ { collectReports: function(aCbObj, aClosure) { function f(aP1, aP2, aK, aU, aA) { aCbObj.callback(aP1, aP2, aK, aU, aA, "Desc.", aClosure); @@ -195,17 +188,17 @@ f("5th", "explicit/b/c/d/e", NONHEAP, BYTES, 20 * KB); f("5th", "explicit/b/c/d/f", NONHEAP, BYTES,-60 * KB); f("5th", "explicit/b/c/g/h", NONHEAP, BYTES, 10 * KB); f("5th", "explicit/b/c/i/j", NONHEAP, BYTES, 5 * KB); } } ]; for (let i = 0; i < fakeReporters2.length; i++) { - mgr.registerReporterEvenIfBlocked(fakeReporters2[i]); + mgr.registerStrongReporterEvenIfBlocked(fakeReporters2[i]); } fakeReporters = fakeReporters.concat(fakeReporters2); ]]> </script> <iframe id="amFrame" height="300" src="about:memory"></iframe> <!-- vary the capitalization to make sure that works --> <iframe id="amvFrame" height="300" src="About:Memory"></iframe> @@ -545,26 +538,17 @@ Other Measurements\n\ \n\ 104,857,600 B ── heap-allocated\n\ \n\ End of 5th\n\ "; function finish() { - // Unregister fake reporters and re-register the real reporters, just in - // case subsequent tests rely on them. - for (let i = 0; i < fakeReporters.length; i++) { - mgr.unregisterReporter(fakeReporters[i]); - } - for (let i = 0; i < realReporters.length; i++) { - mgr.registerReporterEvenIfBlocked(realReporters[i]); - } - mgr.unblockRegistration(); - + mgr.unblockRegistrationAndRestoreOriginalReporters(); SimpleTest.finish(); } // Cut+paste the entire page and check that the cut text matches what we // expect. This tests the output in general and also that the cutting and // pasting works as expected. function test(aFrameId, aVerbose, aExpected, aNext) { SimpleTest.executeSoon(function() {
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul @@ -17,25 +17,18 @@ <![CDATA[ "use strict"; const Cc = Components.classes; const Ci = Components.interfaces; let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); - // Remove all the real reporters; save them to restore at the end. - mgr.blockRegistration(); - let e = mgr.enumerateReporters(); - let realReporters = []; - while (e.hasMoreElements()) { - let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter); - mgr.unregisterReporter(r); - realReporters.push(r); - } + // Hide all the real reporters; we'll restore them at the end. + mgr.blockRegistrationAndHideExistingReporters(); // Setup various fake-but-deterministic reporters. const KB = 1024; const MB = KB * KB; const HEAP = Ci.nsIMemoryReporter.KIND_HEAP; const OTHER = Ci.nsIMemoryReporter.KIND_OTHER; const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES; @@ -61,38 +54,29 @@ f(jk2Path, HEAP, 0.3 * MB); f("explicit/a/l/m", HEAP, 0.1 * MB); f("explicit/a/l/n", HEAP, 0.1 * MB); } } ]; for (let i = 0; i < fakeReporters.length; i++) { - mgr.registerReporterEvenIfBlocked(fakeReporters[i]); + mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]); } ]]> </script> <iframe id="amFrame" height="500" src="about:memory"></iframe> <script type="application/javascript"> <![CDATA[ function finish() { - // Unregister fake reporters and re-register the real reporters, just in - // case subsequent tests rely on them. - for (let i = 0; i < fakeReporters.length; i++) { - mgr.unregisterReporter(fakeReporters[i]); - } - for (let i = 0; i < realReporters.length; i++) { - mgr.registerReporterEvenIfBlocked(realReporters[i]); - } - mgr.unblockRegistration(); - + mgr.unblockRegistrationAndRestoreOriginalReporters(); SimpleTest.finish(); } // Click on the identified element, then cut+paste the entire page and // check that the cut text matches what we expect. function test(aId, aSwap, aExpected, aNext) { let win = document.getElementById("amFrame").contentWindow; if (aId) {
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul @@ -17,25 +17,18 @@ <![CDATA[ "use strict"; const Cc = Components.classes; const Ci = Components.interfaces; let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); - // Remove all the real reporters; save them to restore at the end. - mgr.blockRegistration(); - let e = mgr.enumerateReporters(); - let realReporters = []; - while (e.hasMoreElements()) { - let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter); - mgr.unregisterReporter(r); - realReporters.push(r); - } + // Hide all the real reporters; we'll restore them at the end. + mgr.blockRegistrationAndHideExistingReporters(); // Setup a minimal number of fake reporters. const KB = 1024; const MB = KB * KB; const HEAP = Ci.nsIMemoryReporter.KIND_HEAP; const OTHER = Ci.nsIMemoryReporter.KIND_OTHER; const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES; @@ -48,38 +41,29 @@ f("explicit/a/b", HEAP, 50 * MB, "A b."); f("other/a", OTHER, 0.2 * MB, "Other a."); f("other/b", OTHER, 0.1 * MB, "Other b."); } } ]; for (let i = 0; i < fakeReporters.length; i++) { - mgr.registerReporterEvenIfBlocked(fakeReporters[i]); + mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]); } ]]> </script> <iframe id="amFrame" height="400" src="about:memory"></iframe> <script type="application/javascript"> <![CDATA[ function finish() { - // Unregister fake reporters and re-register the real reporters, just in - // case subsequent tests rely on them. - for (let i = 0; i < fakeReporters.length; i++) { - mgr.unregisterReporter(fakeReporters[i]); - } - for (let i = 0; i < realReporters.length; i++) { - mgr.registerReporterEvenIfBlocked(realReporters[i]); - } - mgr.unblockRegistration(); - + mgr.unblockRegistrationAndRestoreOriginalReporters(); SimpleTest.finish(); } // Load the given file into the frame, then copy+paste the entire frame and // check that the cut text matches what we expect. function test(aFilename, aFilename2, aExpected, aDumpFirst, aNext) { let frame = document.getElementById("amFrame"); frame.focus();
--- a/toolkit/components/places/History.cpp +++ b/toolkit/components/places/History.cpp @@ -26,17 +26,16 @@ #include "mozilla/dom/Link.h" #include "nsDocShellCID.h" #include "mozilla/Services.h" #include "nsThreadUtils.h" #include "nsNetUtil.h" #include "nsIXPConnect.h" #include "mozilla/unused.h" #include "nsContentUtils.h" // for nsAutoScriptBlocker -#include "nsIMemoryReporter.h" #include "mozilla/ipc/URIUtils.h" #include "nsPrintfCString.h" #include "nsTHashtable.h" #include "jsapi.h" // Initial size for the cache holding visited status observers. #define VISIT_OBSERVERS_INITIAL_CACHE_SIZE 128 @@ -1903,69 +1902,59 @@ StoreAndNotifyEmbedVisit(VisitData& aPla (void)NS_ProxyRelease(mainThread, aCallback, true); } VisitData noReferrer; nsCOMPtr<nsIRunnable> event = new NotifyVisitObservers(aPlace, noReferrer); (void)NS_DispatchToMainThread(event); } -class HistoryLinksHashtableReporter MOZ_FINAL : public MemoryUniReporter -{ -public: - HistoryLinksHashtableReporter() - : MemoryUniReporter("explicit/history-links-hashtable", - KIND_HEAP, UNITS_BYTES, -"Memory used by the hashtable that records changes to the visited state of " -"links.") - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - History* history = History::GetService(); - return history ? history->SizeOfIncludingThis(MallocSizeOf) : 0; - } -}; - } // anonymous namespace //////////////////////////////////////////////////////////////////////////////// //// History History* History::gService = nullptr; History::History() - : mShuttingDown(false) + : MemoryUniReporter("explicit/history-links-hashtable", + KIND_HEAP, UNITS_BYTES, +"Memory used by the hashtable that records changes to the visited state of " +"links.") + , mShuttingDown(false) , mShutdownMutex("History::mShutdownMutex") , mObservers(VISIT_OBSERVERS_INITIAL_CACHE_SIZE) , mRecentlyVisitedURIsNextIndex(0) { NS_ASSERTION(!gService, "Ruh-roh! This service has already been created!"); gService = this; nsCOMPtr<nsIObserverService> os = services::GetObserverService(); NS_WARN_IF_FALSE(os, "Observer service was not found!"); if (os) { (void)os->AddObserver(this, TOPIC_PLACES_SHUTDOWN, false); } - - mReporter = new HistoryLinksHashtableReporter(); - NS_RegisterMemoryReporter(mReporter); } History::~History() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); gService = nullptr; NS_ASSERTION(mObservers.Count() == 0, "Not all Links were removed before we disappear!"); } +void +History::InitMemoryReporter() +{ + RegisterWeakMemoryReporter(this); +} + NS_IMETHODIMP History::NotifyVisited(nsIURI* aURI) { NS_ENSURE_ARG(aURI); nsAutoScriptBlocker scriptBlocker; if (XRE_GetProcessType() == GeckoProcessType_Default) { @@ -2227,16 +2216,22 @@ History::FetchPageInfo(VisitData& _place } /* static */ size_t History::SizeOfEntryExcludingThis(KeyClass* aEntry, mozilla::MallocSizeOf aMallocSizeOf, void *) { return aEntry->array.SizeOfExcludingThis(aMallocSizeOf); } +int64_t +History::Amount() +{ + return SizeOfIncludingThis(MallocSizeOf); +} + size_t History::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOfThis) { return aMallocSizeOfThis(this) + mObservers.SizeOfExcludingThis(SizeOfEntryExcludingThis, aMallocSizeOfThis); } /* static */ @@ -2256,16 +2251,17 @@ History::GetService() /* static */ History* History::GetSingleton() { if (!gService) { gService = new History(); NS_ENSURE_TRUE(gService, nullptr); + gService->InitMemoryReporter(); } NS_ADDREF(gService); return gService; } mozIStorageConnection* History::GetDBConn() @@ -2913,18 +2909,19 @@ History::Observe(nsISupports* aSubject, } return NS_OK; } //////////////////////////////////////////////////////////////////////////////// //// nsISupports -NS_IMPL_ISUPPORTS4( +NS_IMPL_ISUPPORTS_INHERITED4( History +, MemoryUniReporter , IHistory , nsIDownloadHistory , mozIAsyncHistory , nsIObserver ) } // namespace places } // namespace mozilla
--- a/toolkit/components/places/History.h +++ b/toolkit/components/places/History.h @@ -15,33 +15,33 @@ #include "Database.h" #include "mozilla/dom/Link.h" #include "nsTHashtable.h" #include "nsString.h" #include "nsURIHashKey.h" #include "nsTObserverArray.h" #include "nsDeque.h" +#include "nsIMemoryReporter.h" #include "nsIObserver.h" #include "mozIStorageConnection.h" -class nsIMemoryReporter; - namespace mozilla { namespace places { struct VisitData; #define NS_HISTORYSERVICE_CID \ {0x0937a705, 0x91a6, 0x417a, {0x82, 0x92, 0xb2, 0x2e, 0xb1, 0x0d, 0xa8, 0x6c}} // Max size of History::mRecentlyVisitedURIs #define RECENTLY_VISITED_URI_SIZE 8 -class History : public IHistory +class History : mozilla::MemoryUniReporter + , public IHistory , public nsIDownloadHistory , public mozIAsyncHistory , public nsIObserver { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_IHISTORY NS_DECL_NSIDOWNLOADHISTORY @@ -80,16 +80,17 @@ public: * Whether or the page was recorded in moz_places, false otherwise. */ nsresult FetchPageInfo(VisitData& _place, bool* _exists); /** * Get the number of bytes of memory this History object is using, * including sizeof(*this)) */ + int64_t Amount() MOZ_OVERRIDE; size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); /** * Obtains a pointer to this service. */ static History* GetService(); /** @@ -126,16 +127,18 @@ public: * Helper function to append a new URI to mRecentlyVisitedURIs. See * mRecentlyVisitedURIs. */ void AppendToRecentlyVisitedURIs(nsIURI* aURI); private: virtual ~History(); + void InitMemoryReporter(); + /** * Obtains a read-write database connection. */ mozIStorageConnection* GetDBConn(); /** * The database handle. This is initialized lazily by the first call to * GetDBConn(), so never use it directly, or, if you really need, always @@ -205,16 +208,14 @@ private: * to avoid saving these locations repeatedly in a short period. */ typedef nsAutoTArray<nsCOMPtr<nsIURI>, RECENTLY_VISITED_URI_SIZE> RecentlyVisitedArray; RecentlyVisitedArray mRecentlyVisitedURIs; RecentlyVisitedArray::index_type mRecentlyVisitedURIsNextIndex; bool IsRecentlyVisitedURI(nsIURI* aURI); - - nsCOMPtr<nsIMemoryReporter> mReporter; }; } // namespace places } // namespace mozilla #endif // mozilla_places_History_h_
--- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -227,49 +227,53 @@ HangReports::GetStacks() const { return mStacks; } uint32_t HangReports::GetDuration(unsigned aIndex) const { return mDurations[aIndex]; } -class TelemetryImpl MOZ_FINAL : public nsITelemetry +class TelemetryImpl MOZ_FINAL + : public MemoryUniReporter + , public nsITelemetry { NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSITELEMETRY public: - TelemetryImpl(); ~TelemetryImpl(); - + + void InitMemoryReporter(); + static bool CanRecord(); static already_AddRefed<nsITelemetry> CreateTelemetryInstance(); static void ShutdownTelemetry(); static void RecordSlowStatement(const nsACString &sql, const nsACString &dbName, uint32_t delay); #if defined(MOZ_ENABLE_PROFILER_SPS) static void RecordChromeHang(uint32_t duration, Telemetry::ProcessedStack &aStack); #endif static void RecordThreadHangStats(Telemetry::ThreadHangStats& aStats); static nsresult GetHistogramEnumId(const char *name, Telemetry::ID *id); - static int64_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); + int64_t Amount() MOZ_OVERRIDE; + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); struct Stat { uint32_t hitCount; uint32_t totalTime; }; struct StmtStats { struct Stat mainThread; struct Stat otherThreads; }; typedef nsBaseHashtableET<nsCStringHashKey, StmtStats> SlowSQLEntryType; private: - size_t SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf); + TelemetryImpl(); static nsCString SanitizeSQL(const nsACString& sql); enum SanitizedState { Sanitized, Unsanitized }; static void StoreSlowSQL(const nsACString &offender, uint32_t delay, SanitizedState state); @@ -321,75 +325,58 @@ private: // AutoHashtable here. nsTHashtable<nsCStringHashKey> mTrackedDBs; Mutex mHashMutex; HangReports mHangReports; Mutex mHangReportsMutex; // mThreadHangStats stores recorded, inactive thread hang stats Vector<Telemetry::ThreadHangStats> mThreadHangStats; Mutex mThreadHangStatsMutex; - nsCOMPtr<nsIMemoryReporter> mReporter; CombinedStacks mLateWritesStacks; // This is collected out of the main thread. bool mCachedTelemetryData; uint32_t mLastShutdownTime; uint32_t mFailedLockCount; nsCOMArray<nsIFetchTelemetryDataCallback> mCallbacks; friend class nsFetchTelemetryData; }; TelemetryImpl* TelemetryImpl::sTelemetry = nullptr; +int64_t +TelemetryImpl::Amount() +{ + return SizeOfIncludingThis(MallocSizeOf); +} + size_t -TelemetryImpl::SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf) +TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { size_t n = aMallocSizeOf(this); // Ignore the hashtables in mAddonMap; they are not significant. n += mAddonMap.SizeOfExcludingThis(nullptr, aMallocSizeOf); n += mHistogramMap.SizeOfExcludingThis(nullptr, aMallocSizeOf); n += mPrivateSQL.SizeOfExcludingThis(nullptr, aMallocSizeOf); n += mSanitizedSQL.SizeOfExcludingThis(nullptr, aMallocSizeOf); n += mTrackedDBs.SizeOfExcludingThis(nullptr, aMallocSizeOf); n += mHangReports.SizeOfExcludingThis(); n += mThreadHangStats.sizeOfExcludingThis(aMallocSizeOf); - return n; -} -int64_t -TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) -{ - int64_t n = 0; - if (sTelemetry) { - n += sTelemetry->SizeOfIncludingThisHelper(aMallocSizeOf); - } - + // It's a bit gross that we measure this other stuff that lives outside of + // TelemetryImpl... oh well. StatisticsRecorder::Histograms hs; StatisticsRecorder::GetHistograms(&hs); - for (HistogramIterator it = hs.begin(); it != hs.end(); ++it) { Histogram *h = *it; n += h->SizeOfIncludingThis(aMallocSizeOf); } + return n; } -class TelemetryReporter MOZ_FINAL : public MemoryUniReporter -{ -public: - TelemetryReporter() - : MemoryUniReporter("explicit/telemetry", KIND_HEAP, UNITS_BYTES, - "Memory used by the telemetry system.") - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - return TelemetryImpl::SizeOfIncludingThis(MallocSizeOf); - } -}; - // A initializer to initialize histogram collection StatisticsRecorder gStatisticsRecorder; // Hardcoded probes struct TelemetryHistogram { uint32_t min; uint32_t max; uint32_t bucketCount; @@ -759,17 +746,17 @@ public: mTelemetry(TelemetryImpl::sTelemetry), mProfileDir(aProfileDir) { } private: const char* mShutdownTimeFilename; nsCOMPtr<nsIFile> mFailedProfileLockFile; - nsCOMPtr<TelemetryImpl> mTelemetry; + nsRefPtr<TelemetryImpl> mTelemetry; nsCOMPtr<nsIFile> mProfileDir; public: void MainThread() { mTelemetry->mCachedTelemetryData = true; for (unsigned int i = 0, n = mTelemetry->mCallbacks.Count(); i < n; ++i) { mTelemetry->mCallbacks[i]->Complete(); } @@ -939,16 +926,18 @@ TelemetryImpl::AsyncFetchTelemetryData(n failedProfileLockFile, profileDir); targetThread->Dispatch(event, NS_DISPATCH_NORMAL); return NS_OK; } TelemetryImpl::TelemetryImpl(): +MemoryUniReporter("explicit/telemetry", KIND_HEAP, UNITS_BYTES, + "Memory used by the telemetry system."), mHistogramMap(Telemetry::HistogramCount), mCanRecord(XRE_GetProcessType() == GeckoProcessType_Default), mHashMutex("Telemetry::mHashMutex"), mHangReportsMutex("Telemetry::mHangReportsMutex"), mThreadHangStatsMutex("Telemetry::mThreadHangStatsMutex"), mCachedTelemetryData(false), mLastShutdownTime(0), mFailedLockCount(0) @@ -964,22 +953,25 @@ mFailedLockCount(0) for (size_t i = 0; i < ArrayLength(trackedDBs); i++) mTrackedDBs.PutEntry(nsDependentCString(trackedDBs[i])); #ifdef DEBUG // Mark immutable to prevent asserts on simultaneous access from multiple threads mTrackedDBs.MarkImmutable(); #endif - mReporter = new TelemetryReporter(); - NS_RegisterMemoryReporter(mReporter); } TelemetryImpl::~TelemetryImpl() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); +} + +void +TelemetryImpl::InitMemoryReporter() { + RegisterWeakMemoryReporter(this); } NS_IMETHODIMP TelemetryImpl::NewHistogram(const nsACString &name, uint32_t min, uint32_t max, uint32_t bucketCount, uint32_t histogramType, JSContext *cx, JS::Value *ret) { Histogram *h; @@ -2023,16 +2015,19 @@ already_AddRefed<nsITelemetry> TelemetryImpl::CreateTelemetryInstance() { NS_ABORT_IF_FALSE(sTelemetry == nullptr, "CreateTelemetryInstance may only be called once, via GetService()"); sTelemetry = new TelemetryImpl(); // AddRef for the local reference NS_ADDREF(sTelemetry); // AddRef for the caller nsCOMPtr<nsITelemetry> ret = sTelemetry; + + sTelemetry->InitMemoryReporter(); + return ret.forget(); } void TelemetryImpl::ShutdownTelemetry() { NS_IF_RELEASE(sTelemetry); } @@ -2247,17 +2242,17 @@ TelemetryImpl::RecordThreadHangStats(Tel if (!sTelemetry || !sTelemetry->mCanRecord) return; MutexAutoLock autoLock(sTelemetry->mThreadHangStatsMutex); sTelemetry->mThreadHangStats.append(Move(aStats)); } -NS_IMPL_ISUPPORTS1(TelemetryImpl, nsITelemetry) +NS_IMPL_ISUPPORTS_INHERITED1(TelemetryImpl, MemoryUniReporter, nsITelemetry) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsITelemetry, TelemetryImpl::CreateTelemetryInstance) #define NS_TELEMETRY_CID \ {0xaea477f2, 0xb3a2, 0x469c, {0xaa, 0x29, 0x0a, 0x82, 0xd1, 0x32, 0xb8, 0x29}} NS_DEFINE_NAMED_CID(NS_TELEMETRY_CID); const Module::CIDEntry kTelemetryCIDs[] = { { &kNS_TELEMETRY_CID, false, nullptr, nsITelemetryConstructor },
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp @@ -9,17 +9,16 @@ #include "nsDebug.h" #include "nsPrintfCString.h" #include "nsTArray.h" #include "nsString.h" #include "nsUrlClassifierPrefixSet.h" #include "nsIUrlClassifierPrefixSet.h" #include "nsIRandomGenerator.h" #include "nsIFile.h" -#include "nsIMemoryReporter.h" #include "nsToolkitCompsCID.h" #include "nsTArray.h" #include "nsThreadUtils.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Mutex.h" #include "mozilla/Telemetry.h" #include "mozilla/FileUtils.h" #include "prlog.h" @@ -31,63 +30,46 @@ using namespace mozilla; static const PRLogModuleInfo *gUrlClassifierPrefixSetLog = nullptr; #define LOG(args) PR_LOG(gUrlClassifierPrefixSetLog, PR_LOG_DEBUG, args) #define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierPrefixSetLog, 4) #else #define LOG(args) #define LOG_ENABLED() (false) #endif -class PrefixSetReporter MOZ_FINAL : public MemoryUniReporter -{ -public: - PrefixSetReporter(nsUrlClassifierPrefixSet* aPrefixSet, - const nsACString& aName) - : MemoryUniReporter( - nsPrintfCString( - "explicit/storage/prefix-set/%s", - (!aName.IsEmpty() ? PromiseFlatCString(aName).get() : "?!") - ).get(), - KIND_HEAP, UNITS_BYTES, - "Memory used by the prefix set for a URL classifier.") - , mPrefixSet(aPrefixSet) - {} - -private: - int64_t Amount() MOZ_OVERRIDE - { - return mPrefixSet->SizeOfIncludingThis(MallocSizeOf); - } - - nsUrlClassifierPrefixSet* mPrefixSet; -}; - -NS_IMPL_ISUPPORTS1(nsUrlClassifierPrefixSet, nsIUrlClassifierPrefixSet) +NS_IMPL_ISUPPORTS2( + nsUrlClassifierPrefixSet, nsIUrlClassifierPrefixSet, nsIMemoryReporter) nsUrlClassifierPrefixSet::nsUrlClassifierPrefixSet() : mHasPrefixes(false) + , mMemoryReportPath() { #if defined(PR_LOGGING) if (!gUrlClassifierPrefixSetLog) gUrlClassifierPrefixSetLog = PR_NewLogModule("UrlClassifierPrefixSet"); #endif } NS_IMETHODIMP nsUrlClassifierPrefixSet::Init(const nsACString& aName) { - mReporter = new PrefixSetReporter(this, aName); - NS_RegisterMemoryReporter(mReporter); + mMemoryReportPath = + nsPrintfCString( + "explicit/storage/prefix-set/%s", + (!aName.IsEmpty() ? PromiseFlatCString(aName).get() : "?!") + ); + + RegisterWeakMemoryReporter(this); return NS_OK; } nsUrlClassifierPrefixSet::~nsUrlClassifierPrefixSet() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); } NS_IMETHODIMP nsUrlClassifierPrefixSet::SetPrefixes(const uint32_t* aArray, uint32_t aLength) { if (aLength <= 0) { if (mHasPrefixes) { LOG(("Clearing PrefixSet")); @@ -263,18 +245,31 @@ nsUrlClassifierPrefixSet::Contains(uint3 if (diff == 0) { *aFound = true; } return NS_OK; } +NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(UrlClassifierMallocSizeOf) + +NS_IMETHODIMP +nsUrlClassifierPrefixSet::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData) +{ + return aHandleReport->Callback( + EmptyCString(), mMemoryReportPath, KIND_HEAP, UNITS_BYTES, + SizeOfIncludingThis(UrlClassifierMallocSizeOf), + NS_LITERAL_CSTRING("Memory used by the prefix set for a URL classifier."), + aData); +} + size_t -nsUrlClassifierPrefixSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) +nsUrlClassifierPrefixSet::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { size_t n = 0; n += aMallocSizeOf(this); n += mDeltas.SizeOfExcludingThis(aMallocSizeOf); n += mIndexPrefixes.SizeOfExcludingThis(aMallocSizeOf); n += mIndexStarts.SizeOfExcludingThis(aMallocSizeOf); return n; }
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h +++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h @@ -5,64 +5,65 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsUrlClassifierPrefixSet_h_ #define nsUrlClassifierPrefixSet_h_ #include "nsISupportsUtils.h" #include "nsID.h" #include "nsIFile.h" +#include "nsIMemoryReporter.h" #include "nsIMutableArray.h" #include "nsIUrlClassifierPrefixSet.h" #include "nsTArray.h" #include "nsToolkitCompsCID.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Mutex.h" #include "mozilla/CondVar.h" #include "mozilla/FileUtils.h" -class nsIMemoryReporter; - -class nsUrlClassifierPrefixSet : public nsIUrlClassifierPrefixSet +class nsUrlClassifierPrefixSet + : public nsIUrlClassifierPrefixSet + , public nsIMemoryReporter { public: nsUrlClassifierPrefixSet(); virtual ~nsUrlClassifierPrefixSet(); NS_IMETHOD Init(const nsACString& aName); NS_IMETHOD SetPrefixes(const uint32_t* aArray, uint32_t aLength); NS_IMETHOD GetPrefixes(uint32_t* aCount, uint32_t** aPrefixes); NS_IMETHOD Contains(uint32_t aPrefix, bool* aFound); NS_IMETHOD IsEmpty(bool* aEmpty); NS_IMETHOD LoadFromFile(nsIFile* aFile); NS_IMETHOD StoreToFile(nsIFile* aFile); - NS_DECL_ISUPPORTS + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIMEMORYREPORTER - // Return the estimated size of the set on disk and in memory, - // in bytes + // Return the estimated size of the set on disk and in memory, in bytes. size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); protected: static const uint32_t DELTAS_LIMIT = 100; static const uint32_t MAX_INDEX_DIFF = (1 << 16); static const uint32_t PREFIXSET_VERSION_MAGIC = 1; - nsCOMPtr<nsIMemoryReporter> mReporter; - nsresult MakePrefixSet(const uint32_t* aArray, uint32_t aLength); uint32_t BinSearch(uint32_t start, uint32_t end, uint32_t target); nsresult LoadFromFd(mozilla::AutoFDClose& fileFd); nsresult StoreToFd(mozilla::AutoFDClose& fileFd); // boolean indicating whether |setPrefixes| has been // called with a non-empty array. bool mHasPrefixes; // the prefix for each index. FallibleTArray<uint32_t> mIndexPrefixes; // the value corresponds to the beginning of the run // (an index in |_deltas|) for the index FallibleTArray<uint32_t> mIndexStarts; // array containing deltas from indices. FallibleTArray<uint16_t> mDeltas; + + nsCString mMemoryReportPath; }; #endif
--- a/xpcom/base/AvailableMemoryTracker.cpp +++ b/xpcom/base/AvailableMemoryTracker.cpp @@ -505,20 +505,20 @@ void Activate() Preferences::AddUintVarCache(&sLowPhysicalMemoryThreshold, "memory.low_physical_memory_threshold_mb", 0); Preferences::AddUintVarCache(&sLowCommitSpaceThreshold, "memory.low_commit_space_threshold_mb", 128); Preferences::AddUintVarCache(&sLowMemoryNotificationIntervalMS, "memory.low_memory_notification_interval_ms", 10000); - NS_RegisterMemoryReporter(new LowCommitSpaceEventsReporter()); - NS_RegisterMemoryReporter(new LowMemoryEventsPhysicalReporter()); + RegisterStrongMemoryReporter(new LowCommitSpaceEventsReporter()); + RegisterStrongMemoryReporter(new LowMemoryEventsPhysicalReporter()); if (sizeof(void*) == 4) { - NS_RegisterMemoryReporter(new LowMemoryEventsVirtualReporter()); + RegisterStrongMemoryReporter(new LowMemoryEventsVirtualReporter()); } RegisterLowMemoryEventsVirtualDistinguishedAmount(LowMemoryEventsVirtualDistinguishedAmount); RegisterLowMemoryEventsPhysicalDistinguishedAmount(LowMemoryEventsPhysicalDistinguishedAmount); sHooksActive = true; #endif // This object is held alive by the observer service. nsRefPtr<nsMemoryPressureWatcher> watcher = new nsMemoryPressureWatcher();
--- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -990,17 +990,17 @@ enum ccType { #ifdef MOZ_NUWA_PROCESS #include "ipc/Nuwa.h" #endif //////////////////////////////////////////////////////////////////////// // Top level structure for the cycle collector. //////////////////////////////////////////////////////////////////////// -class nsCycleCollector : public nsISupports +class nsCycleCollector : public MemoryMultiReporter { NS_DECL_ISUPPORTS bool mCollectionInProgress; // mScanInProgress should be false when we're collecting white objects. bool mScanInProgress; CycleCollectorResults mResults; TimeStamp mCollectionStart; @@ -1015,18 +1015,16 @@ class nsCycleCollector : public nsISuppo nsCycleCollectorParams mParams; uint32_t mWhiteNodeCount; CC_BeforeUnlinkCallback mBeforeUnlinkCB; CC_ForgetSkippableCallback mForgetSkippableCB; - nsCOMPtr<nsIMemoryReporter> mReporter; - nsPurpleBuffer mPurpleBuf; uint32_t mUnmergedNeeded; uint32_t mMergedInARow; public: nsCycleCollector(); virtual ~nsCycleCollector(); @@ -1051,17 +1049,20 @@ public: uint32_t SuspectedCount(); void ForgetSkippable(bool aRemoveChildlessNodes, bool aAsyncSnowWhiteFreeing); bool FreeSnowWhite(bool aUntilNoSWInPurpleBuffer); bool Collect(ccType aCCType, nsICycleCollectorListener *aManualListener); void Shutdown(); - void SizeOfIncludingThis(MallocSizeOf aMallocSizeOf, + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData); + + void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, size_t *aObjectSize, size_t *aGraphNodesSize, size_t *aGraphEdgesSize, size_t *aWeakMapsSize, size_t *aPurpleBufferSize) const; private: void CheckThreadSafety(); @@ -1076,17 +1077,17 @@ private: void ScanWeakMaps(); // returns whether anything was collected bool CollectWhite(); void CleanupAfterCollection(); }; -NS_IMPL_ISUPPORTS1(nsCycleCollector, nsISupports) +NS_IMPL_ISUPPORTS_INHERITED0(nsCycleCollector, MemoryMultiReporter) /** * GraphWalker is templatized over a Visitor class that must provide * the following two methods: * * bool ShouldVisitNode(PtrInfo const *pi); * void VisitNode(PtrInfo *pi); */ @@ -2470,120 +2471,108 @@ nsCycleCollector::CollectWhite() nsCycleCollector_dispatchDeferredDeletion(false); return count > 0; } //////////////////////// -// Memory reporter +// Memory reporting //////////////////////// -class CycleCollectorReporter MOZ_FINAL : public MemoryMultiReporter +NS_IMETHODIMP +nsCycleCollector::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData) { - public: - CycleCollectorReporter(nsCycleCollector* aCollector) - : MemoryMultiReporter("cycle-collector"), - mCollector(aCollector) - {} - - NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb, - nsISupports* aClosure) - { - size_t objectSize, graphNodesSize, graphEdgesSize, weakMapsSize, - purpleBufferSize; - mCollector->SizeOfIncludingThis(MallocSizeOf, - &objectSize, - &graphNodesSize, &graphEdgesSize, - &weakMapsSize, - &purpleBufferSize); - - #define REPORT(_path, _amount, _desc) \ - do { \ - size_t amount = _amount; /* evaluate |_amount| only once */ \ - if (amount > 0) { \ - nsresult rv; \ - rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \ - nsIMemoryReporter::KIND_HEAP, \ - nsIMemoryReporter::UNITS_BYTES, _amount, \ - NS_LITERAL_CSTRING(_desc), aClosure); \ - if (NS_WARN_IF(NS_FAILED(rv))) \ - return rv; \ - } \ - } while (0) - - REPORT("explicit/cycle-collector/collector-object", objectSize, - "Memory used for the cycle collector object itself."); - - REPORT("explicit/cycle-collector/graph-nodes", graphNodesSize, - "Memory used for the nodes of the cycle collector's graph. " - "This should be zero when the collector is idle."); - - REPORT("explicit/cycle-collector/graph-edges", graphEdgesSize, - "Memory used for the edges of the cycle collector's graph. " - "This should be zero when the collector is idle."); - - REPORT("explicit/cycle-collector/weak-maps", weakMapsSize, - "Memory used for the representation of weak maps in the " - "cycle collector's graph. " - "This should be zero when the collector is idle."); - - REPORT("explicit/cycle-collector/purple-buffer", purpleBufferSize, - "Memory used for the cycle collector's purple buffer."); - - #undef REPORT - - return NS_OK; - } - - private: - NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf) - - nsCycleCollector* mCollector; + size_t objectSize, graphNodesSize, graphEdgesSize, weakMapsSize, + purpleBufferSize; + SizeOfIncludingThis(MallocSizeOf, + &objectSize, + &graphNodesSize, &graphEdgesSize, + &weakMapsSize, + &purpleBufferSize); + +#define REPORT(_path, _amount, _desc) \ + do { \ + size_t amount = _amount; /* evaluate |_amount| only once */ \ + if (amount > 0) { \ + nsresult rv; \ + rv = aHandleReport->Callback(EmptyCString(), \ + NS_LITERAL_CSTRING(_path), \ + KIND_HEAP, UNITS_BYTES, _amount, \ + NS_LITERAL_CSTRING(_desc), \ + aData); \ + if (NS_WARN_IF(NS_FAILED(rv))) \ + return rv; \ + } \ + } while (0) + + REPORT("explicit/cycle-collector/collector-object", objectSize, + "Memory used for the cycle collector object itself."); + + REPORT("explicit/cycle-collector/graph-nodes", graphNodesSize, + "Memory used for the nodes of the cycle collector's graph. " + "This should be zero when the collector is idle."); + + REPORT("explicit/cycle-collector/graph-edges", graphEdgesSize, + "Memory used for the edges of the cycle collector's graph. " + "This should be zero when the collector is idle."); + + REPORT("explicit/cycle-collector/weak-maps", weakMapsSize, + "Memory used for the representation of weak maps in the " + "cycle collector's graph. " + "This should be zero when the collector is idle."); + + REPORT("explicit/cycle-collector/purple-buffer", purpleBufferSize, + "Memory used for the cycle collector's purple buffer."); + +#undef REPORT + + return NS_OK; }; //////////////////////////////////////////////////////////////////////// // Collector implementation //////////////////////////////////////////////////////////////////////// nsCycleCollector::nsCycleCollector() : + MemoryMultiReporter("cycle-collector"), mCollectionInProgress(false), mScanInProgress(false), mJSRuntime(nullptr), mThread(NS_GetCurrentThread()), mWhiteNodeCount(0), mBeforeUnlinkCB(nullptr), mForgetSkippableCB(nullptr), - mReporter(nullptr), mUnmergedNeeded(0), mMergedInARow(0) { } nsCycleCollector::~nsCycleCollector() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); } void nsCycleCollector::RegisterJSRuntime(CycleCollectedJSRuntime *aJSRuntime) { if (mJSRuntime) Fault("multiple registrations of cycle collector JS runtime", aJSRuntime); mJSRuntime = aJSRuntime; - // We can't register the reporter in nsCycleCollector() because that runs + // We can't register as a reporter in nsCycleCollector() because that runs // before the memory reporter manager is initialized. So we do it here // instead. static bool registered = false; if (!registered) { - NS_RegisterMemoryReporter(new CycleCollectorReporter(this)); + RegisterWeakMemoryReporter(this); registered = true; } } void nsCycleCollector::ForgetJSRuntime() { if (!mJSRuntime) @@ -2854,17 +2843,17 @@ nsCycleCollector::Shutdown() if (PR_GetEnv("XPCOM_CC_RUN_DURING_SHUTDOWN")) #endif { ShutdownCollect(); } } void -nsCycleCollector::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf, +nsCycleCollector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, size_t *aObjectSize, size_t *aGraphNodesSize, size_t *aGraphEdgesSize, size_t *aWeakMapsSize, size_t *aPurpleBufferSize) const { *aObjectSize = aMallocSizeOf(this);
--- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -173,42 +173,51 @@ interface nsIMemoryReporter : nsISupport }; [scriptable, function, uuid(548b3909-c04d-4ca6-8466-b8bee3837457)] interface nsIFinishReportingCallback : nsISupports { void callback(in nsISupports data); }; -[scriptable, builtinclass, uuid(41c667f4-16b3-424f-95d9-a6f903f72eb2)] +[scriptable, builtinclass, uuid(9245d89e-6523-45f9-bc15-a69789e33cbb)] interface nsIMemoryReporterManager : nsISupports { /* * Initialize. */ void init(); /* * Register the given nsIMemoryReporter. After a reporter is registered, * it will be available via enumerateReporters(). The Manager service - * will hold a strong reference to the given reporter. + * will hold a strong reference to the given reporter, and will be + * responsible for freeing the reporter at shutdown. */ - void registerReporter(in nsIMemoryReporter reporter); + void registerStrongReporter(in nsIMemoryReporter reporter); /* - * Unregister the given memory reporter. + * Like registerReporter, but the Manager service will hold a weak reference + * to the given reporter. The reporter should be unregistered before + * shutdown. */ - void unregisterReporter(in nsIMemoryReporter reporter); + void registerWeakReporter(in nsIMemoryReporter reporter); + + /* + * Unregister the given memory reporter, which must have been registered with + * registerWeakReporter(). + */ + void unregisterWeakReporter(in nsIMemoryReporter reporter); /* * These functions should only be used for testing purposes. */ - void blockRegistration(); - void unblockRegistration(); - void registerReporterEvenIfBlocked(in nsIMemoryReporter aReporter); + void blockRegistrationAndHideExistingReporters(); + void unblockRegistrationAndRestoreOriginalReporters(); + void registerStrongReporterEvenIfBlocked(in nsIMemoryReporter aReporter); /* * Return an enumerator of nsIMemoryReporters that are currently registered * in the current process. WARNING: this does not do anything with child * processes. Use getReports() if you want measurements from child * processes. */ nsISimpleEnumerator enumerateReporters(); @@ -359,24 +368,28 @@ interface nsIMemoryReporterManager : nsI #include "nsTArray.h" class nsPIDOMWindow; // nsIHandleReportCallback is a better name, but keep nsIMemoryReporterCallback // around for backwards compatibility. typedef nsIMemoryReporterCallback nsIHandleReportCallback; -// Note that the memory reporters are held in an nsCOMArray, which means -// that individual reporters should be referenced with |nsIMemoryReporter *| -// instead of nsCOMPtr<nsIMemoryReporter>. +namespace mozilla { + +// Register a memory reporter. The manager service will hold a strong +// reference to this reporter. +XPCOM_API(nsresult) RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter); -XPCOM_API(nsresult) NS_RegisterMemoryReporter(nsIMemoryReporter* aReporter); -XPCOM_API(nsresult) NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter); +// Register a memory reporter. The manager service will hold a weak reference +// to this reporter. +XPCOM_API(nsresult) RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter); -namespace mozilla { +// Unregister a weak memory reporter. +XPCOM_API(nsresult) UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter); // The memory reporter manager provides access to several distinguished // amounts via attributes. Some of these amounts are provided by Gecko // components that cannot be accessed directly from XPCOM code. So we provide // the following functions for those components to be registered with the // manager. typedef int64_t (*InfallibleAmountFn)();
--- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -708,17 +708,17 @@ private: int64_t Amount() MOZ_OVERRIDE { return HeapOverheadRatio(); } }; #endif // HAVE_JEMALLOC_STATS // Why is this here? At first glance, you'd think it could be defined and // registered with nsMemoryReporterManager entirely within nsAtomTable.cpp. // However, the obvious time to register it is when the table is initialized, // and that happens before XPCOM components are initialized, which means the -// NS_RegisterMemoryReporter call fails. So instead we do it here. +// RegisterStrongMemoryReporter call fails. So instead we do it here. class AtomTablesReporter MOZ_FINAL : public MemoryUniReporter { public: AtomTablesReporter() : MemoryUniReporter("explicit/atom-tables", KIND_HEAP, UNITS_BYTES, "Memory used by the dynamic and static atoms tables.") {} private: @@ -796,108 +796,122 @@ NS_IMETHODIMP nsMemoryReporterManager::Init() { #if defined(HAVE_JEMALLOC_STATS) && defined(XP_LINUX) if (!jemalloc_stats) return NS_ERROR_FAILURE; #endif #ifdef HAVE_JEMALLOC_STATS - RegisterReporter(new HeapAllocatedReporter); - RegisterReporter(new HeapOverheadWasteReporter); - RegisterReporter(new HeapOverheadBookkeepingReporter); - RegisterReporter(new HeapOverheadPageCacheReporter); - RegisterReporter(new HeapCommittedReporter); - RegisterReporter(new HeapOverheadRatioReporter); + RegisterStrongReporter(new HeapAllocatedReporter()); + RegisterStrongReporter(new HeapOverheadWasteReporter()); + RegisterStrongReporter(new HeapOverheadBookkeepingReporter()); + RegisterStrongReporter(new HeapOverheadPageCacheReporter()); + RegisterStrongReporter(new HeapCommittedReporter()); + RegisterStrongReporter(new HeapOverheadRatioReporter()); #endif #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS - RegisterReporter(new VsizeReporter); - RegisterReporter(new ResidentReporter); + RegisterStrongReporter(new VsizeReporter()); + RegisterStrongReporter(new ResidentReporter()); #endif #ifdef HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER - RegisterReporter(new VsizeMaxContiguousReporter); + RegisterStrongReporter(new VsizeMaxContiguousReporter()); #endif #ifdef HAVE_RESIDENT_UNIQUE_REPORTER - RegisterReporter(new ResidentUniqueReporter); + RegisterStrongReporter(new ResidentUniqueReporter()); #endif #ifdef HAVE_PAGE_FAULT_REPORTERS - RegisterReporter(new PageFaultsSoftReporter); - RegisterReporter(new PageFaultsHardReporter); + RegisterStrongReporter(new PageFaultsSoftReporter()); + RegisterStrongReporter(new PageFaultsHardReporter()); #endif #ifdef HAVE_PRIVATE_REPORTER - RegisterReporter(new PrivateReporter); + RegisterStrongReporter(new PrivateReporter()); #endif - RegisterReporter(new AtomTablesReporter); + RegisterStrongReporter(new AtomTablesReporter()); #ifdef MOZ_DMD - RegisterReporter(new mozilla::dmd::DMDReporter); + RegisterStrongReporter(new mozilla::dmd::DMDReporter()); #endif #if defined(XP_LINUX) nsMemoryInfoDumper::Initialize(); #endif return NS_OK; } namespace { -/** - * HastableEnumerator takes an nsTHashtable<nsISupportsHashKey>& in its - * constructor and creates an nsISimpleEnumerator from its contents. - * - * The resultant enumerator works over a copy of the hashtable, so it's safe to - * mutate or destroy the hashtable after the enumerator is created. - */ - -class HashtableEnumerator MOZ_FINAL : public nsISimpleEnumerator +// ReporterEnumerator takes the two hashtables of reporters in its constructor +// and creates an nsISimpleEnumerator from its contents. +// +// The resultant enumerator works over a copy of the hashtable elements, so +// it's safe to mutate or destroy the hashtables after the enumerator is +// created. +// +class ReporterEnumerator MOZ_FINAL : public nsISimpleEnumerator { public: - HashtableEnumerator(nsTHashtable<nsISupportsHashKey>& aHashtable) - : mIndex(0) + ReporterEnumerator( + nsMemoryReporterManager::StrongReportersTable* aStrongReporters, + nsMemoryReporterManager::WeakReportersTable* aWeakReporters) + : mIndex(0) { - aHashtable.EnumerateEntries(EnumeratorFunc, this); + aStrongReporters->EnumerateEntries(StrongEnumerator, this); + aWeakReporters->EnumerateEntries(WeakEnumerator, this); } NS_DECL_ISUPPORTS NS_DECL_NSISIMPLEENUMERATOR private: static PLDHashOperator - EnumeratorFunc(nsISupportsHashKey* aEntry, void* aData); + StrongEnumerator(nsISupportsHashKey* aEntry, void* aData); + + static PLDHashOperator + WeakEnumerator(nsPtrHashKey<nsISupports>* aEntry, void* aData); uint32_t mIndex; nsCOMArray<nsISupports> mArray; }; -NS_IMPL_ISUPPORTS1(HashtableEnumerator, nsISimpleEnumerator) +NS_IMPL_ISUPPORTS1(ReporterEnumerator, nsISimpleEnumerator) /* static */ PLDHashOperator -HashtableEnumerator::EnumeratorFunc(nsISupportsHashKey* aElem, void* aData) +ReporterEnumerator::StrongEnumerator(nsISupportsHashKey* aElem, void* aData) { - HashtableEnumerator* enumerator = static_cast<HashtableEnumerator*>(aData); + ReporterEnumerator* enumerator = static_cast<ReporterEnumerator*>(aData); + enumerator->mArray.AppendObject(aElem->GetKey()); + return PL_DHASH_NEXT; +} + +/* static */ PLDHashOperator +ReporterEnumerator::WeakEnumerator(nsPtrHashKey<nsISupports>* aElem, + void* aData) +{ + ReporterEnumerator* enumerator = static_cast<ReporterEnumerator*>(aData); enumerator->mArray.AppendObject(aElem->GetKey()); return PL_DHASH_NEXT; } NS_IMETHODIMP -HashtableEnumerator::HasMoreElements(bool* aResult) +ReporterEnumerator::HasMoreElements(bool* aResult) { *aResult = mIndex < mArray.Length(); return NS_OK; } NS_IMETHODIMP -HashtableEnumerator::GetNext(nsISupports** aNext) +ReporterEnumerator::GetNext(nsISupports** aNext) { if (mIndex < mArray.Length()) { nsCOMPtr<nsISupports> next = mArray.ObjectAt(mIndex); next.forget(aNext); mIndex++; return NS_OK; } @@ -905,39 +919,47 @@ HashtableEnumerator::GetNext(nsISupports return NS_ERROR_FAILURE; } } // anonymous namespace nsMemoryReporterManager::nsMemoryReporterManager() : mMutex("nsMemoryReporterManager::mMutex"), mIsRegistrationBlocked(false), + mStrongReporters(new StrongReportersTable()), + mWeakReporters(new WeakReportersTable()), + mSavedStrongReporters(nullptr), + mSavedWeakReporters(nullptr), mNumChildProcesses(0), mNextGeneration(1), mGetReportsState(nullptr) { } nsMemoryReporterManager::~nsMemoryReporterManager() { + delete mStrongReporters; + delete mWeakReporters; + NS_ASSERTION(!mSavedStrongReporters, "failed to restore strong reporters"); + NS_ASSERTION(!mSavedWeakReporters, "failed to restore weak reporters"); } NS_IMETHODIMP nsMemoryReporterManager::EnumerateReporters(nsISimpleEnumerator** aResult) { // Memory reporters are not necessarily threadsafe, so this function must // be called from the main thread. if (!NS_IsMainThread()) { MOZ_CRASH(); } mozilla::MutexAutoLock autoLock(mMutex); - nsRefPtr<HashtableEnumerator> enumerator = - new HashtableEnumerator(mReporters); + nsRefPtr<ReporterEnumerator> enumerator = + new ReporterEnumerator(mStrongReporters, mWeakReporters); enumerator.forget(aResult); return NS_OK; } //#define DEBUG_CHILD_PROCESS_MEMORY_REPORTING 1 #ifdef DEBUG_CHILD_PROCESS_MEMORY_REPORTING #define MEMORY_REPORTING_LOG(format, ...) \ @@ -1020,22 +1042,19 @@ nsMemoryReporterManager::GetReports( mNumChildProcesses, aHandleReport, aHandleReportData, aFinishReporting, aFinishReportingData); } // Get reports for this process. - nsRefPtr<HashtableEnumerator> e; - { - mozilla::MutexAutoLock autoLock(mMutex); - e = new HashtableEnumerator(mReporters); - } bool more; + nsCOMPtr<nsISimpleEnumerator> e; + EnumerateReporters(getter_AddRefs(e)); while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) { nsCOMPtr<nsIMemoryReporter> r; e->GetNext(getter_AddRefs(r)); r->CollectReports(aHandleReport, aHandleReportData); } // If there are no child processes, we can finish up immediately. return (mNumChildProcesses == 0) @@ -1147,104 +1166,142 @@ nsMemoryReporterManager::FinishReporting (void)mGetReportsState->mFinishReporting->Callback( mGetReportsState->mFinishReportingData); delete mGetReportsState; mGetReportsState = nullptr; } static void -DebugAssertRefcountIsNonZero(nsISupports* aObj) +CrashIfRefcountIsZero(nsISupports* aObj) { -#ifdef DEBUG // This will probably crash if the object's refcount is 0. uint32_t refcnt = NS_ADDREF(aObj); - MOZ_ASSERT(refcnt >= 2); + if (refcnt <= 1) { + MOZ_CRASH("CrashIfRefcountIsZero: refcount is zero"); + } NS_RELEASE(aObj); -#endif } nsresult nsMemoryReporterManager::RegisterReporterHelper( - nsIMemoryReporter* aReporter, bool aForce) + nsIMemoryReporter* aReporter, bool aForce, bool aStrong) { // This method is thread-safe. mozilla::MutexAutoLock autoLock(mMutex); - if ((mIsRegistrationBlocked && !aForce) || mReporters.Contains(aReporter)) { + if (mIsRegistrationBlocked && !aForce) { + return NS_ERROR_FAILURE; + } + + if (mStrongReporters->Contains(aReporter) || + mWeakReporters->Contains(aReporter)) + { return NS_ERROR_FAILURE; } - // This method needs to be safe even if |aReporter| has a refcnt of 0, so - // we take a kung fu death grip before calling PutEntry. Otherwise, if - // PutEntry addref'ed and released |aReporter| before finally addref'ing it - // for good, it would free aReporter! + // If |aStrong| is true, |aReporter| may have a refcnt of 0, so we take + // a kung fu death grip before calling PutEntry. Otherwise, if PutEntry + // addref'ed and released |aReporter| before finally addref'ing it for + // good, it would free aReporter! The kung fu death grip could itself be + // problematic if PutEntry didn't addref |aReporter| (because then when the + // death grip goes out of scope, we would delete the reporter). In debug + // mode, we check that this doesn't happen. // - // The kung fu death grip could itself be problematic if PutEntry didn't - // addref |aReporter| (because then when the death grip goes out of scope, - // we would delete the reporter). In debug mode, we check that this - // doesn't happen. - - { + // If |aStrong| is false, we require that |aReporter| have a non-zero + // refcnt. + // + if (aStrong) { nsCOMPtr<nsIMemoryReporter> kungFuDeathGrip = aReporter; - mReporters.PutEntry(aReporter); + mStrongReporters->PutEntry(aReporter); + CrashIfRefcountIsZero(aReporter); + } else { + CrashIfRefcountIsZero(aReporter); + mWeakReporters->PutEntry(aReporter); } - DebugAssertRefcountIsNonZero(aReporter); - return NS_OK; } NS_IMETHODIMP -nsMemoryReporterManager::RegisterReporter(nsIMemoryReporter* aReporter) +nsMemoryReporterManager::RegisterStrongReporter(nsIMemoryReporter* aReporter) { - return RegisterReporterHelper(aReporter, /* force = */ false); + return RegisterReporterHelper(aReporter, /* force = */ false, + /* strong = */ true); } NS_IMETHODIMP -nsMemoryReporterManager::RegisterReporterEvenIfBlocked( - nsIMemoryReporter* aReporter) +nsMemoryReporterManager::RegisterWeakReporter(nsIMemoryReporter* aReporter) { - return RegisterReporterHelper(aReporter, /* force = */ true); + return RegisterReporterHelper(aReporter, /* force = */ false, + /* strong = */ false); } NS_IMETHODIMP -nsMemoryReporterManager::UnregisterReporter(nsIMemoryReporter* aReporter) +nsMemoryReporterManager::RegisterStrongReporterEvenIfBlocked( + nsIMemoryReporter* aReporter) +{ + return RegisterReporterHelper(aReporter, /* force = */ true, + /* strong = */ true); +} + +NS_IMETHODIMP +nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter) { // This method is thread-safe. mozilla::MutexAutoLock autoLock(mMutex); - if (!mReporters.Contains(aReporter)) { - return NS_ERROR_FAILURE; + MOZ_ASSERT(!mStrongReporters->Contains(aReporter)); + + if (mWeakReporters->Contains(aReporter)) { + mWeakReporters->RemoveEntry(aReporter); + return NS_OK; } - mReporters.RemoveEntry(aReporter); - return NS_OK; + return NS_ERROR_FAILURE; } NS_IMETHODIMP -nsMemoryReporterManager::BlockRegistration() +nsMemoryReporterManager::BlockRegistrationAndHideExistingReporters() { // This method is thread-safe. mozilla::MutexAutoLock autoLock(mMutex); if (mIsRegistrationBlocked) { return NS_ERROR_FAILURE; } mIsRegistrationBlocked = true; + + // Hide the existing reporters, saving them for later restoration. + MOZ_ASSERT(!mSavedStrongReporters); + MOZ_ASSERT(!mSavedWeakReporters); + mSavedStrongReporters = mStrongReporters; + mSavedWeakReporters = mWeakReporters; + mStrongReporters = new StrongReportersTable(); + mWeakReporters = new WeakReportersTable(); + return NS_OK; } NS_IMETHODIMP -nsMemoryReporterManager::UnblockRegistration() +nsMemoryReporterManager::UnblockRegistrationAndRestoreOriginalReporters() { // This method is thread-safe. mozilla::MutexAutoLock autoLock(mMutex); if (!mIsRegistrationBlocked) { return NS_ERROR_FAILURE; } + + // Banish the current reporters, and restore the hidden ones. + delete mStrongReporters; + delete mWeakReporters; + mStrongReporters = mSavedStrongReporters; + mWeakReporters = mSavedWeakReporters; + mSavedStrongReporters = nullptr; + mSavedWeakReporters = nullptr; + mIsRegistrationBlocked = false; return NS_OK; } // This is just a wrapper for int64_t that implements nsISupports, so it can be // passed to nsIMemoryReporter::CollectReports. class Int64Wrapper MOZ_FINAL : public nsISupports { public: @@ -1616,37 +1673,47 @@ nsMemoryReporterManager::SizeOfTab(nsIDO } // Most memory reporters don't need thread safety, but some do. Make them all // thread-safe just to be safe. Memory reporters are created and destroyed // infrequently enough that the performance cost should be negligible. NS_IMPL_ISUPPORTS1(MemoryUniReporter, nsIMemoryReporter) NS_IMPL_ISUPPORTS1(MemoryMultiReporter, nsIMemoryReporter) +namespace mozilla { + nsresult -NS_RegisterMemoryReporter(nsIMemoryReporter* aReporter) +RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter) { nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); if (!mgr) { return NS_ERROR_FAILURE; } - return mgr->RegisterReporter(aReporter); + return mgr->RegisterStrongReporter(aReporter); } nsresult -NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter) +RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter) { nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); if (!mgr) { return NS_ERROR_FAILURE; } - return mgr->UnregisterReporter(aReporter); + return mgr->RegisterWeakReporter(aReporter); } -namespace mozilla { +nsresult +UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter) +{ + nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } + return mgr->UnregisterWeakReporter(aReporter); +} #define GET_MEMORY_REPORTER_MANAGER(mgr) \ nsRefPtr<nsMemoryReporterManager> mgr = \ nsMemoryReporterManager::GetOrCreate(); \ if (!mgr) { \ return NS_ERROR_FAILURE; \ }
--- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -31,16 +31,19 @@ public: // Gets the memory reporter manager service. static nsMemoryReporterManager* GetOrCreate() { nsCOMPtr<nsIMemoryReporterManager> imgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); return static_cast<nsMemoryReporterManager*>(imgr.get()); } + typedef nsTHashtable<nsISupportsHashKey> StrongReportersTable; + typedef nsTHashtable<nsPtrHashKey<nsISupports> > WeakReportersTable; + void IncrementNumChildProcesses(); void DecrementNumChildProcesses(); // Inter-process memory reporting proceeds as follows. // // - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER) // synchronously gets memory reports for the current process, tells all // child processes to get memory reports, and sets up some state @@ -141,25 +144,32 @@ public: mozilla::JSSizeOfTabFn mJS; mozilla::NonJSSizeOfTabFn mNonJS; SizeOfTabFns() { mozilla::PodZero(this); } }; SizeOfTabFns mSizeOfTabFns; private: - nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter, bool aForce); + nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter, + bool aForce, bool aStrongRef); static void TimeoutCallback(nsITimer* aTimer, void* aData); static const uint32_t kTimeoutLengthMS = 5000; - nsTHashtable<nsISupportsHashKey> mReporters; Mutex mMutex; bool mIsRegistrationBlocked; + StrongReportersTable* mStrongReporters; + WeakReportersTable* mWeakReporters; + + // These two are only used for testing purposes. + StrongReportersTable* mSavedStrongReporters; + WeakReportersTable* mSavedWeakReporters; + uint32_t mNumChildProcesses; uint32_t mNextGeneration; struct GetReportsState { uint32_t mGeneration; nsCOMPtr<nsITimer> mTimer; uint32_t mNumChildProcesses; uint32_t mNumChildProcessesCompleted;
--- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -578,17 +578,17 @@ NS_InitXPCOM2(nsIServiceManager* *result nullptr, NS_XPCOM_STARTUP_OBSERVER_ID); #ifdef XP_WIN CreateAnonTempFileRemover(); #endif // The memory reporter manager is up and running -- register a reporter for // ICU's memory usage. - NS_RegisterMemoryReporter(new ICUReporter()); + RegisterStrongMemoryReporter(new ICUReporter()); mozilla::Telemetry::Init(); mozilla::HangMonitor::Startup(); mozilla::BackgroundHangMonitor::Startup(); #ifdef MOZ_VISUAL_EVENT_TRACER mozilla::eventtracer::Init();
--- a/xpcom/components/nsCategoryManager.cpp +++ b/xpcom/components/nsCategoryManager.cpp @@ -12,17 +12,16 @@ #include "prio.h" #include "prprf.h" #include "prlock.h" #include "nsCOMPtr.h" #include "nsTHashtable.h" #include "nsClassHashtable.h" #include "nsIFactory.h" #include "nsIStringEnumerator.h" -#include "nsIMemoryReporter.h" #include "nsSupportsPrimitives.h" #include "nsComponentManagerUtils.h" #include "nsServiceManagerUtils.h" #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsReadableUtils.h" #include "nsCRT.h" #include "nsQuickSort.h" @@ -396,32 +395,17 @@ CategoryEnumerator::enumfunc_createenume return PL_DHASH_NEXT; } // // nsCategoryManager implementations // -NS_IMPL_QUERY_INTERFACE1(nsCategoryManager, nsICategoryManager) - -class XPCOMCategoryManagerReporter MOZ_FINAL : public MemoryUniReporter -{ -public: - XPCOMCategoryManagerReporter() - : MemoryUniReporter("explicit/xpcom/category-manager", - KIND_HEAP, UNITS_BYTES, - "Memory used for the XPCOM category manager.") - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - return nsCategoryManager::SizeOfIncludingThis(MallocSizeOf); - } -}; +NS_IMPL_QUERY_INTERFACE_INHERITED1(nsCategoryManager, MemoryUniReporter, nsICategoryManager) NS_IMETHODIMP_(nsrefcnt) nsCategoryManager::AddRef() { return 2; } NS_IMETHODIMP_(nsrefcnt) @@ -452,34 +436,35 @@ nsCategoryManager::Create(nsISupports* a { if (aOuter) return NS_ERROR_NO_AGGREGATION; return GetSingleton()->QueryInterface(aIID, aResult); } nsCategoryManager::nsCategoryManager() - : mLock("nsCategoryManager") + : MemoryUniReporter("explicit/xpcom/category-manager", + KIND_HEAP, UNITS_BYTES, + "Memory used for the XPCOM category manager.") + , mLock("nsCategoryManager") , mSuppressNotifications(false) - , mReporter(nullptr) { PL_INIT_ARENA_POOL(&mArena, "CategoryManagerArena", NS_CATEGORYMANAGER_ARENA_SIZE); } void nsCategoryManager::InitMemoryReporter() { - mReporter = new XPCOMCategoryManagerReporter(); - NS_RegisterMemoryReporter(mReporter); + RegisterWeakMemoryReporter(this); } nsCategoryManager::~nsCategoryManager() { - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); // the hashtable contains entries that must be deleted before the arena is // destroyed, or else you will have PRLocks undestroyed and other Really // Bad Stuff (TM) mTable.Clear(); PL_FinishArenaPool(&mArena); } @@ -488,38 +473,35 @@ inline CategoryNode* nsCategoryManager::get_category(const char* aName) { CategoryNode* node; if (!mTable.Get(aName, &node)) { return nullptr; } return node; } -/* static */ int64_t -nsCategoryManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) +int64_t +nsCategoryManager::Amount() { - return nsCategoryManager::gCategoryManager - ? nsCategoryManager::gCategoryManager->SizeOfIncludingThisHelper( - aMallocSizeOf) - : 0; + return SizeOfIncludingThis(MallocSizeOf); } static size_t SizeOfCategoryManagerTableEntryExcludingThis(nsDepCharHashKey::KeyType aKey, const nsAutoPtr<CategoryNode> &aData, MallocSizeOf aMallocSizeOf, void* aUserArg) { // We don't measure the string pointed to by aKey because it's a non-owning // pointer. return aData.get()->SizeOfExcludingThis(aMallocSizeOf); } size_t -nsCategoryManager::SizeOfIncludingThisHelper(MallocSizeOf aMallocSizeOf) +nsCategoryManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { size_t n = aMallocSizeOf(this); n += PL_SizeOfArenaPoolExcludingPool(&mArena, aMallocSizeOf); n += mTable.SizeOfExcludingThis(SizeOfCategoryManagerTableEntryExcludingThis, aMallocSizeOf); @@ -578,17 +560,19 @@ nsCategoryManager::NotifyObservers( cons return; nsresult rv = entry->SetData(nsDependentCString(aEntryName)); if (NS_FAILED(rv)) return; r = new CategoryNotificationRunnable(entry, aTopic, aCategoryName); } else { - r = new CategoryNotificationRunnable(this, aTopic, aCategoryName); + r = new CategoryNotificationRunnable( + NS_ISUPPORTS_CAST(nsICategoryManager*, this), + aTopic, aCategoryName); } NS_DispatchToMainThread(r); } NS_IMETHODIMP nsCategoryManager::GetCategoryEntry( const char *aCategoryName, const char *aEntryName,
--- a/xpcom/components/nsCategoryManager.h +++ b/xpcom/components/nsCategoryManager.h @@ -6,16 +6,17 @@ #ifndef NSCATEGORYMANAGER_H #define NSCATEGORYMANAGER_H #include "prio.h" #include "plarena.h" #include "nsClassHashtable.h" #include "nsICategoryManager.h" +#include "nsIMemoryReporter.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Mutex.h" #include "mozilla/Attributes.h" class nsIMemoryReporter; /* 16d222a6-1dd2-11b2-b693-f38b02c021b2 */ #define NS_CATEGORYMANAGER_CID \ @@ -92,17 +93,18 @@ private: /** * The main implementation of nsICategoryManager. * * This implementation is thread-safe. */ class nsCategoryManager MOZ_FINAL - : public nsICategoryManager + : public mozilla::MemoryUniReporter + , public nsICategoryManager { public: NS_DECL_ISUPPORTS NS_DECL_NSICATEGORYMANAGER /** * Suppress or unsuppress notifications of category changes to the * observer service. This is to be used by nsComponentManagerImpl @@ -117,32 +119,30 @@ public: char** aOldValue = nullptr); static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult); void InitMemoryReporter(); static nsCategoryManager* GetSingleton(); static void Destroy(); - static int64_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); + int64_t Amount() MOZ_OVERRIDE; private: static nsCategoryManager* gCategoryManager; nsCategoryManager(); ~nsCategoryManager(); - size_t SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf); + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); CategoryNode* get_category(const char* aName); void NotifyObservers(const char* aTopic, const char* aCategoryName, // must be a static string const char* aEntryName); PLArenaPool mArena; nsClassHashtable<nsDepCharHashKey, CategoryNode> mTable; mozilla::Mutex mLock; bool mSuppressNotifications; - - nsCOMPtr<nsIMemoryReporter> mReporter; }; #endif
--- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -35,17 +35,16 @@ #include "nsDirectoryService.h" #include "nsDirectoryServiceDefs.h" #include "nsCategoryManager.h" #include "nsCategoryManagerUtils.h" #include "xptiprivate.h" #include "mozilla/MemoryReporting.h" #include "mozilla/XPTInterfaceInfoManager.h" #include "nsIConsoleService.h" -#include "nsIMemoryReporter.h" #include "nsIObserverService.h" #include "nsISimpleEnumerator.h" #include "nsIStringEnumerator.h" #include "nsXPCOM.h" #include "nsXPCOMPrivate.h" #include "nsISupportsPrimitives.h" #include "nsIClassInfo.h" #include "nsLocalFile.h" @@ -278,50 +277,35 @@ CloneAndAppend(nsIFile* aBase, const nsA f->AppendNative(append); return f.forget(); } //////////////////////////////////////////////////////////////////////////////// // nsComponentManagerImpl //////////////////////////////////////////////////////////////////////////////// -class XPCOMComponentManagerReporter MOZ_FINAL : public MemoryUniReporter -{ -public: - XPCOMComponentManagerReporter() - : MemoryUniReporter("explicit/xpcom/component-manager", - KIND_HEAP, UNITS_BYTES, - "Memory used for the XPCOM component manager.") - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - return nsComponentManagerImpl::gComponentManager - ? nsComponentManagerImpl::gComponentManager->SizeOfIncludingThis( - MallocSizeOf) - : 0; - } -}; - nsresult nsComponentManagerImpl::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult) { if (aOuter) return NS_ERROR_NO_AGGREGATION; if (!gComponentManager) return NS_ERROR_FAILURE; return gComponentManager->QueryInterface(aIID, aResult); } static const int CONTRACTID_HASHTABLE_INITIAL_SIZE = 2048; nsComponentManagerImpl::nsComponentManagerImpl() - : mFactories(CONTRACTID_HASHTABLE_INITIAL_SIZE) + : MemoryUniReporter("explicit/xpcom/component-manager", + KIND_HEAP, UNITS_BYTES, + "Memory used for the XPCOM component manager.") + , mFactories(CONTRACTID_HASHTABLE_INITIAL_SIZE) , mContractIDs(CONTRACTID_HASHTABLE_INITIAL_SIZE) , mLock("nsComponentManagerImpl.mLock") , mStatus(NOT_INITIALIZED) { } nsTArray<const mozilla::Module*>* nsComponentManagerImpl::sStaticModules; @@ -409,18 +393,17 @@ nsresult nsComponentManagerImpl::Init() cl->type = NS_COMPONENT_LOCATION; cl->location.Init(greOmnijar, "chrome.manifest"); } RereadChromeManifests(false); nsCategoryManager::GetSingleton()->SuppressNotifications(false); - mReporter = new XPCOMComponentManagerReporter(); - NS_RegisterMemoryReporter(mReporter); + RegisterWeakMemoryReporter(this); // Unfortunately, we can't register the nsCategoryManager memory reporter // in its constructor (which is triggered by the GetSingleton() call // above) because the memory reporter manager isn't initialized at that // point. So we wait until now. nsCategoryManager::GetSingleton()->InitMemoryReporter(); mStatus = NORMAL; @@ -795,18 +778,17 @@ nsresult nsComponentManagerImpl::Shutdow { PR_ASSERT(NORMAL == mStatus); mStatus = SHUTDOWN_IN_PROGRESS; // Shutdown the component manager PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown.")); - NS_UnregisterMemoryReporter(mReporter); - mReporter = nullptr; + UnregisterWeakMemoryReporter(this); // Release all cached factories mContractIDs.Clear(); mFactories.Clear(); // XXX release the objects, don't just clear mLoaderMap.Clear(); mKnownModules.Clear(); mKnownStaticModules.Clear(); @@ -831,23 +813,24 @@ nsComponentManagerImpl::~nsComponentMana PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction.")); if (SHUTDOWN_COMPLETE != mStatus) Shutdown(); PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed.")); } -NS_IMPL_ISUPPORTS5(nsComponentManagerImpl, - nsIComponentManager, - nsIServiceManager, - nsIComponentRegistrar, - nsISupportsWeakReference, - nsIInterfaceRequestor) - +NS_IMPL_ISUPPORTS_INHERITED5( + nsComponentManagerImpl, + MemoryUniReporter, + nsIComponentManager, + nsIServiceManager, + nsIComponentRegistrar, + nsISupportsWeakReference, + nsIInterfaceRequestor) nsresult nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result) { NS_WARNING("This isn't supported"); // fall through to QI as anything QIable is a superset of what can be // got via the GetInterface() return QueryInterface(uuid, result); @@ -1702,18 +1685,24 @@ SizeOfContractIDsEntryExcludingThis(nsCS MallocSizeOf aMallocSizeOf, void* aUserArg) { // We don't measure the nsFactoryEntry data because its owned by mFactories // (which measures them in SizeOfFactoriesEntryExcludingThis). return aKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf); } +int64_t +nsComponentManagerImpl::Amount() +{ + return SizeOfIncludingThis(MallocSizeOf); +} + size_t -nsComponentManagerImpl::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) +nsComponentManagerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { size_t n = aMallocSizeOf(this); n += mLoaderMap.SizeOfExcludingThis(nullptr, aMallocSizeOf); n += mFactories.SizeOfExcludingThis(SizeOfFactoriesEntryExcludingThis, aMallocSizeOf); n += mContractIDs.SizeOfExcludingThis(SizeOfContractIDsEntryExcludingThis, aMallocSizeOf); n += sStaticModules->SizeOfIncludingThis(aMallocSizeOf); n += sModuleLocations->SizeOfIncludingThis(aMallocSizeOf);
--- a/xpcom/components/nsComponentManager.h +++ b/xpcom/components/nsComponentManager.h @@ -6,16 +6,17 @@ #ifndef nsComponentManager_h__ #define nsComponentManager_h__ #include "nsXPCOM.h" #include "xpcom-private.h" #include "nsIComponentManager.h" #include "nsIComponentRegistrar.h" +#include "nsIMemoryReporter.h" #include "nsIServiceManager.h" #include "nsIFile.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Module.h" #include "mozilla/ModuleLoader.h" #include "mozilla/Mutex.h" #include "nsXULAppAPI.h" #include "nsNativeComponentLoader.h" @@ -33,17 +34,16 @@ #include "nsInterfaceHashtable.h" #include "nsClassHashtable.h" #include "nsTArray.h" #include "mozilla/Omnijar.h" #include "mozilla/Attributes.h" struct nsFactoryEntry; -class nsIMemoryReporter; class nsIServiceManager; struct PRThread; #define NS_COMPONENTMANAGER_CID \ { /* 91775d60-d5dc-11d2-92fb-00e09805570f */ \ 0x91775d60, \ 0xd5dc, \ 0x11d2, \ @@ -114,17 +114,18 @@ private: mozilla::Mutex mMutex; volatile PRThread* mOwnerThread; }; typedef mozilla::BaseAutoLock<SafeMutex> SafeMutexAutoLock; typedef mozilla::BaseAutoUnlock<SafeMutex> SafeMutexAutoUnlock; class nsComponentManagerImpl MOZ_FINAL - : public nsIComponentManager + : public mozilla::MemoryUniReporter + , public nsIComponentManager , public nsIServiceManager , public nsSupportsWeakReference , public nsIComponentRegistrar , public nsIInterfaceRequestor { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIINTERFACEREQUESTOR @@ -307,22 +308,21 @@ public: inline PendingServiceInfo* AddPendingService(const nsCID& aServiceCID, PRThread* aThread); inline void RemovePendingService(const nsCID& aServiceCID); inline PRThread* GetPendingServiceThread(const nsCID& aServiceCID) const; nsTArray<PendingServiceInfo> mPendingServices; + int64_t Amount() MOZ_OVERRIDE; size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); private: ~nsComponentManagerImpl(); - - nsCOMPtr<nsIMemoryReporter> mReporter; }; #define NS_MAX_FILENAME_LEN 1024 #define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24) struct nsFactoryEntry
--- a/xpcom/ds/nsObserverList.h +++ b/xpcom/ds/nsObserverList.h @@ -41,17 +41,17 @@ struct ObserverRef return static_cast<nsIWeakReference*>((nsISupports*) ref); } bool operator==(nsISupports* b) const { return ref == b; } }; class nsObserverList : public nsCharPtrHashKey { - friend class mozilla::ObserverServiceReporter; + friend class nsObserverService; public: nsObserverList(const char *key) : nsCharPtrHashKey(key) { MOZ_COUNT_CTOR(nsObserverList); } ~nsObserverList() { MOZ_COUNT_DTOR(nsObserverList); } nsresult AddObserver(nsIObserver* anObserver, bool ownsWeak);
--- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -6,17 +6,16 @@ #include "prlog.h" #include "nsAutoPtr.h" #include "nsIObserverService.h" #include "nsIObserver.h" #include "nsObserverService.h" #include "nsObserverList.h" #include "nsThreadUtils.h" #include "nsEnumeratorUtils.h" -#include "nsIMemoryReporter.h" #include "mozilla/net/NeckoCommon.h" #include "mozilla/Services.h" #define NOTIFY_GLOBAL_OBSERVERS #if defined(PR_LOGGING) // Log module for nsObserverService logging... // @@ -37,51 +36,39 @@ GetObserverServiceLog() } #define LOG(x) PR_LOG(GetObserverServiceLog(), PR_LOG_DEBUG, x) #else #define LOG(x) #endif /* PR_LOGGING */ namespace mozilla { -class ObserverServiceReporter MOZ_FINAL : public MemoryMultiReporter -{ -public: - ObserverServiceReporter() - : MemoryMultiReporter("observer-service") - {} - - NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb, - nsISupports *aClosure); - -protected: - static const size_t kSuspectReferentCount = 100; - static PLDHashOperator CountReferents(nsObserverList* aObserverList, - void* aClosure); -}; - struct SuspectObserver { SuspectObserver(const char* aTopic, size_t aReferentCount) : topic(aTopic), referentCount(aReferentCount) {} const char* topic; size_t referentCount; }; struct ObserverServiceReferentCount { ObserverServiceReferentCount() : numStrong(0), numWeakAlive(0), numWeakDead(0) {} size_t numStrong; size_t numWeakAlive; size_t numWeakDead; nsTArray<SuspectObserver> suspectObservers; }; +} // namespace mozilla + +using namespace mozilla; + PLDHashOperator -ObserverServiceReporter::CountReferents(nsObserverList* aObserverList, - void* aClosure) +nsObserverService::CountReferents(nsObserverList* aObserverList, + void* aClosure) { if (!aObserverList) { return PL_DHASH_NEXT; } ObserverServiceReferentCount* referentCount = static_cast<ObserverServiceReferentCount*>(aClosure); @@ -115,122 +102,104 @@ ObserverServiceReporter::CountReferents( SuspectObserver suspect(aObserverList->GetKey(), total); referentCount->suspectObservers.AppendElement(suspect); } return PL_DHASH_NEXT; } NS_IMETHODIMP -ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb, - nsISupports* aClosure) +nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData) { - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); - nsObserverService* service = static_cast<nsObserverService*>(os.get()); - if (!service) { - return NS_OK; - } - ObserverServiceReferentCount referentCount; - service->mObserverTopicTable.EnumerateEntries(CountReferents, - &referentCount); + 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, + rv = aHandleReport->Callback(/* process */ EmptyCString(), + suspectPath, KIND_OTHER, UNITS_COUNT, suspect.referentCount, NS_LITERAL_CSTRING("A topic with a suspiciously large number of " "referents. This may be symptomatic of a leak " "if the number of referents is high with " "respect to the number of windows."), - aClosure); + aData); if (NS_WARN_IF(NS_FAILED(rv))) return rv; } - rv = cb->Callback(/* process */ EmptyCString(), + rv = aHandleReport->Callback(/* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/strong"), - nsIMemoryReporter::KIND_OTHER, - nsIMemoryReporter::UNITS_COUNT, - referentCount.numStrong, + KIND_OTHER, UNITS_COUNT, referentCount.numStrong, NS_LITERAL_CSTRING("The number of strong references held by the " "observer service."), - aClosure); + aData); if (NS_WARN_IF(NS_FAILED(rv))) return rv; - rv = cb->Callback(/* process */ EmptyCString(), + rv = aHandleReport->Callback(/* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/weak/alive"), - nsIMemoryReporter::KIND_OTHER, - nsIMemoryReporter::UNITS_COUNT, - referentCount.numWeakAlive, + KIND_OTHER, UNITS_COUNT, referentCount.numWeakAlive, NS_LITERAL_CSTRING("The number of weak references held by the " "observer service that are still alive."), - aClosure); + aData); if (NS_WARN_IF(NS_FAILED(rv))) return rv; - rv = cb->Callback(/* process */ EmptyCString(), + rv = aHandleReport->Callback(/* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/weak/dead"), - nsIMemoryReporter::KIND_OTHER, - nsIMemoryReporter::UNITS_COUNT, - referentCount.numWeakDead, + KIND_OTHER, UNITS_COUNT, referentCount.numWeakDead, NS_LITERAL_CSTRING("The number of weak references held by the " "observer service that are dead."), - aClosure); + aData); if (NS_WARN_IF(NS_FAILED(rv))) return rv; return NS_OK; } -} // namespace mozilla - -using namespace mozilla; - //////////////////////////////////////////////////////////////////////////////// // nsObserverService Implementation -NS_IMPL_ISUPPORTS2(nsObserverService, nsIObserverService, nsObserverService) +NS_IMPL_ISUPPORTS_INHERITED2( + nsObserverService, + MemoryMultiReporter, + nsIObserverService, + nsObserverService) nsObserverService::nsObserverService() : - mShuttingDown(false), mReporter(nullptr) + MemoryMultiReporter("observer-service"), + mShuttingDown(false) { } nsObserverService::~nsObserverService(void) { Shutdown(); } void nsObserverService::RegisterReporter() { - mReporter = new ObserverServiceReporter(); - NS_RegisterMemoryReporter(mReporter); + RegisterWeakMemoryReporter(this); } void nsObserverService::Shutdown() { - if (mReporter) { - NS_UnregisterMemoryReporter(mReporter); - } + UnregisterWeakMemoryReporter(this); mShuttingDown = true; mObserverTopicTable.Clear(); } nsresult nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
--- a/xpcom/ds/nsObserverService.h +++ b/xpcom/ds/nsObserverService.h @@ -3,32 +3,30 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsObserverService_h___ #define nsObserverService_h___ #include "nsIObserverService.h" #include "nsObserverList.h" +#include "nsIMemoryReporter.h" #include "nsTHashtable.h" #include "mozilla/Attributes.h" // {D07F5195-E3D1-11d2-8ACD-00105A1B8860} #define NS_OBSERVERSERVICE_CID \ { 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } } class nsIMemoryReporter; -namespace mozilla { -class ObserverServiceReporter; -} // namespace mozilla - -class nsObserverService MOZ_FINAL : public nsIObserverService { - friend class mozilla::ObserverServiceReporter; - +class nsObserverService MOZ_FINAL + : public mozilla::MemoryMultiReporter + , public nsIObserverService +{ public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_OBSERVERSERVICE_CID) nsObserverService(); NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIOBSERVERSERVICE @@ -36,20 +34,25 @@ public: static nsresult Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); // Unmark any strongly held observers implemented in JS so the cycle // collector will not traverse them. NS_IMETHOD UnmarkGrayStrongObservers(); + NS_IMETHOD CollectReports(nsIHandleReportCallback *aHandleReport, + nsISupports *aData); + private: ~nsObserverService(void); void RegisterReporter(); + static const size_t kSuspectReferentCount = 100; + static PLDHashOperator CountReferents(nsObserverList* aObserverList, + void* aClosure); bool mShuttingDown; nsTHashtable<nsObserverList> mObserverTopicTable; - nsCOMPtr<nsIMemoryReporter> mReporter; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsObserverService, NS_OBSERVERSERVICE_CID) #endif /* nsObserverService_h___ */
--- a/xpcom/reflect/xptinfo/public/XPTInterfaceInfoManager.h +++ b/xpcom/reflect/xptinfo/public/XPTInterfaceInfoManager.h @@ -3,16 +3,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_XPTInterfaceInfoManager_h_ #define mozilla_XPTInterfaceInfoManager_h_ #include "nsIInterfaceInfoManager.h" +#include "nsIMemoryReporter.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Mutex.h" #include "mozilla/ReentrantMonitor.h" #include "nsDataHashtable.h" template<typename T> class nsCOMArray; class nsIMemoryReporter; @@ -20,17 +21,18 @@ class XPTHeader; class XPTInterfaceDirectoryEntry; class xptiInterfaceEntry; class xptiInterfaceInfo; class xptiTypelibGuts; namespace mozilla { class XPTInterfaceInfoManager MOZ_FINAL - : public nsIInterfaceInfoManager + : public mozilla::MemoryUniReporter + , public nsIInterfaceInfoManager { NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIINTERFACEINFOMANAGER public: // GetSingleton() is infallible static XPTInterfaceInfoManager* GetSingleton(); static void FreeInterfaceInfoManager(); @@ -42,25 +44,26 @@ public: static Mutex& GetResolveLock() { return GetSingleton()->mResolveLock; } xptiInterfaceEntry* GetInterfaceEntryForIID(const nsIID *iid); size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); - - static int64_t GetXPTIWorkingSetSize(); + int64_t Amount() MOZ_OVERRIDE; private: XPTInterfaceInfoManager(); ~XPTInterfaceInfoManager(); + void InitMemoryReporter(); + void RegisterXPTHeader(XPTHeader* aHeader); - + // idx is the index of this interface in the XPTHeader void VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface, uint16_t idx, xptiTypelibGuts* typelib); private: class xptiWorkingSet @@ -104,15 +107,13 @@ private: // XXX xptiInterfaceInfo want's to poke at the working set itself friend class ::xptiInterfaceInfo; friend class ::xptiInterfaceEntry; friend class ::xptiTypelibGuts; xptiWorkingSet mWorkingSet; Mutex mResolveLock; - - nsCOMPtr<nsIMemoryReporter> mReporter; }; } #endif
--- a/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp +++ b/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp @@ -1,112 +1,112 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Implementation of xptiInterfaceInfoManager. */ +#include "mozilla/XPTInterfaceInfoManager.h" + +#include "mozilla/FileUtils.h" #include "mozilla/MemoryReporting.h" -#include "mozilla/XPTInterfaceInfoManager.h" +#include "mozilla/StaticPtr.h" #include "xptiprivate.h" #include "nsDependentString.h" #include "nsString.h" #include "nsISupportsArray.h" #include "nsArrayEnumerator.h" #include "nsDirectoryService.h" -#include "mozilla/FileUtils.h" #include "nsIMemoryReporter.h" using namespace mozilla; -NS_IMPL_ISUPPORTS1(XPTInterfaceInfoManager, - nsIInterfaceInfoManager) +NS_IMPL_ISUPPORTS_INHERITED1( + XPTInterfaceInfoManager, + MemoryUniReporter, + nsIInterfaceInfoManager) -static XPTInterfaceInfoManager* gInterfaceInfoManager = nullptr; +static StaticRefPtr<XPTInterfaceInfoManager> gInterfaceInfoManager; #ifdef DEBUG static int gCallCount = 0; #endif size_t -XPTInterfaceInfoManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) +XPTInterfaceInfoManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) { size_t n = aMallocSizeOf(this); ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); // The entries themselves are allocated out of an arena accounted // for elsewhere, so don't measure them n += mWorkingSet.mIIDTable.SizeOfExcludingThis(nullptr, aMallocSizeOf); n += mWorkingSet.mNameTable.SizeOfExcludingThis(nullptr, aMallocSizeOf); return n; } -class XPTIWorkingSetReporter MOZ_FINAL : public MemoryUniReporter +int64_t +XPTInterfaceInfoManager::Amount() { -public: - XPTIWorkingSetReporter() - : MemoryUniReporter("explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, - "Memory used by the XPCOM typelib system.") - {} -private: - int64_t Amount() MOZ_OVERRIDE - { - size_t n = gInterfaceInfoManager - ? gInterfaceInfoManager->SizeOfIncludingThis(MallocSizeOf) - : 0; + size_t n = SizeOfIncludingThis(MallocSizeOf); - // Measure gXPTIStructArena here, too. This is a bit grotty because it - // doesn't belong to the xptiInterfaceInfoManager, but there's no - // obviously better place to measure it. - n += XPT_SizeOfArena(gXPTIStructArena, MallocSizeOf); + // Measure gXPTIStructArena here, too. This is a bit grotty because it + // doesn't belong to the XPTIInterfaceInfoManager, but there's no + // obviously better place to measure it. + n += XPT_SizeOfArena(gXPTIStructArena, MallocSizeOf); - return n; - } -}; + return n; +} // static XPTInterfaceInfoManager* XPTInterfaceInfoManager::GetSingleton() { if (!gInterfaceInfoManager) { gInterfaceInfoManager = new XPTInterfaceInfoManager(); - NS_ADDREF(gInterfaceInfoManager); + gInterfaceInfoManager->InitMemoryReporter(); } return gInterfaceInfoManager; } void XPTInterfaceInfoManager::FreeInterfaceInfoManager() { - NS_IF_RELEASE(gInterfaceInfoManager); + gInterfaceInfoManager = nullptr; } XPTInterfaceInfoManager::XPTInterfaceInfoManager() - : mWorkingSet(), + : MemoryUniReporter("explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, + "Memory used by the XPCOM typelib system."), + mWorkingSet(), mResolveLock("XPTInterfaceInfoManager.mResolveLock") { - mReporter = new XPTIWorkingSetReporter(); - NS_RegisterMemoryReporter(mReporter); } XPTInterfaceInfoManager::~XPTInterfaceInfoManager() { // We only do this on shutdown of the service. mWorkingSet.InvalidateInterfaceInfos(); - NS_UnregisterMemoryReporter(mReporter); + UnregisterWeakMemoryReporter(this); gInterfaceInfoManager = nullptr; #ifdef DEBUG gCallCount = 0; #endif } void +XPTInterfaceInfoManager::InitMemoryReporter() +{ + RegisterWeakMemoryReporter(this); +} + +void XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length) { XPTState *state = XPT_NewXDRState(XPT_DECODE, buf, length); if (!state) return; XPTCursor cursor; if (!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) {