凡走過必留下痕跡 – 如何獲得 memory allocation 的 footprint

作者:
瀏覽:364

在開發軟體的過程中,難免會碰上 memory leak 或是碰上需要減少記憶體使用量的情況。碰到這種事情時,我們會需要 memory allocation 的 footprint,才能夠找出問題點。開發 Firefox 桌面版、Firefox for Android,或是 Firefox OS 的過程當然也不例外。

這三者尋找 memory allocation 的 footprint 的方式是很類似的,本篇文章將會以 Firefox OS 為例,介紹如何得到 about:memory 中會看到的 heap-unclassified 這塊記憶體的 footprint

1. 在 .userconfig 中加上以下參數( .userconfig 位於 B2G working directory 下,第一次需要自己動手加),才能編譯出我們所需要的 gecko。DMD 是打開 “dark mass detector" 紀錄 footprint,NOOPT 是為了確保解譯出來 footprint 正確無誤。

export B2G_NOOPT=1
export MOZ_DMD=1

2. 編譯完成且安裝正確的 gecko 到手機上後,如果在手機的 logcat 中可以看到以下資訊,那就是使用到正確的 gecko 啦!

I/DMD     (  305): $DMD = '1'
I/DMD     (  305): DMD is enabled

3. 如何拿到、並正確解譯 memory allocation 的 footprint?我們要先進入 B2G working directory 下的 tools 這個資料夾,執行 get_about_memory.py. 以下我以一隻叫開發代號叫做 unagi 的手機為例:

./get_about_memory.py --product unagi --gecko-objdir ../objdir-gecko --no-auto-open --remove-cache --toolchain-prefix arm-linux-androideabi- --toolchain-dir ../prebuilt/linux-x86/toolchain/arm-linux-androideabi-4.4.x/bin/

第三步需要特別注意的三個參數:
3-a. –product 是用來指定我們在 config 時的裝置名稱
3-b. –gecko-objdir 是用來指定 gecko obj 的資料夾
3-c. 如果沒有加上 –no-auto-open,則會直接開啟 Firefox 瀏覽器,可以查看 about:memory 的內容
3-d*. 目前 Firefox OS 使用的 toolchain 跟 android ICS 4.0.4 一樣,所以 –toolchain-prefix 以及 –toolchain-dir 這兩組參數就使用 android ICS 4.0.4 的。如果將來新版的 Firefox OS 用了不同的 toolchain,我們也是可以透過執行 “. setup.sh" 來查看正確的版本以及位置。

第三步做完以後,會在 tools 裡面產生 about-memory-[流水號] 的資料夾。about-memory 裡面放的就是 b2g process 以及所有 app process 的記憶體使用狀況,和長得像是下面這樣, memory allocation 的 footprint 了。

Once-reported: ~1 block in stack trace record 569 of 1,102
 ~4,093 bytes (~4,093 requested / ~0 slop)
 0.01% of the heap (52.76% cumulative);  0.02% of once-reported (87.84% cumulative)
 Allocated at
   malloc /home/alan/git/B2G/gecko/memory/build/replace_malloc.c:151 (0x40150e36 libmozglue.so+0x4e36)
   js_malloc /home/alan/git/B2G/objdir-gecko-noopt-dmd/dist/include/js/Utility.h:153 (0x417872fa libxul.so+0xdce2fa)
   JSRuntime::malloc_(unsigned int, JSContext*) /home/alan/git/B2G/gecko/js/src/jscntxt.h:1000 (0x42371660 libxul.so+0x19b8660)
   unsigned short* JSRuntime::pod_malloc(unsigned int, JSContext*) /home/alan/git/B2G/gecko/js/src/jscntxt.h:1048 (0x423a5efa libxul.so+0x19ecefa)
   unsigned short* JSContext::pod_malloc(unsigned int) /home/alan/git/B2G/gecko/js/src/jscntxt.h:1544 (0x423a566c libxul.so+0x19ec66c)
   js_NewStringCopyN(JSContext*, unsigned short const*, unsigned int) /home/alan/git/B2G/gecko/js/src/jsstr.cpp:3359 (0x424c3178 libxul.so+0x1b0a178)
   AtomizeInline /home/alan/git/B2G/gecko/js/src/jsatom.cpp:272 (0x4239e038 libxul.so+0x19e5038)
   js::frontend::TokenStream::atomize(JSContext*, js::Vector&) /home/alan/git/B2G/gecko/js/src/frontend/TokenStream.cpp:1274 (0x425882a6 libxul.so+0x1bcf2a6)
   js::frontend::TokenStream::getToken() /home/alan/git/B2G/gecko/js/src/frontend/TokenStream.h:600 (0x423d2d10 libxul.so+0x1a19d10)
   js::frontend::TokenStream::matchToken(js::frontend::TokenKind) /home/alan/git/B2G/gecko/js/src/frontend/TokenStream.h:660 (0x4254a404 libxul.so+0x1b91404)
   js::frontend::TokenStream::matchToken(js::frontend::TokenKind, unsigned int) /home/alan/git/B2G/gecko/js/src/frontend/TokenStream.h:668 (0x4256c4a2 libxul.so+0x1bb34a2)
   js::frontend::Parser::argumentList(js::frontend::ParseNode*) /home/alan/git/B2G/gecko/js/src/frontend/Parser.cpp:5398 (0x4257ab86 libxul.so+0x1bc1b86)
   js::frontend::Parser::memberExpr(bool) /home/alan/git/B2G/gecko/js/src/frontend/Parser.cpp:5672 (0x4257b6d4 libxul.so+0x1bc26d4)
   js::frontend::Parser::unaryExpr() /home/alan/git/B2G/gecko/js/src/frontend/Parser.cpp:4685 (0x425790e6 libxul.so+0x1bc00e6)
   js::frontend::Parser::mulExpr1i() /home/alan/git/B2G/gecko/js/src/frontend/Parser.cpp:4218 (0x425782a4 libxul.so+0x1bbf2a4)
   js::frontend::Parser::expr() /home/alan/git/B2G/gecko/js/src/frontend/Parser.cpp:4174 (0x42576342 libxul.so+0x1bbd342)
   js::frontend::Parser::expressionStatement() /home/alan/git/B2G/gecko/js/src/frontend/Parser.cpp:3659 (0x4257500a libxul.so+0x1bbc00a)
   js::frontend::Parser::statement() /home/alan/git/B2G/gecko/js/src/frontend/Parser.cpp:4045 (0x42575f20 libxul.so+0x1bbcf20)
   js::frontend::CompileScript(JSContext*, JS::Handle, js::StackFrame*, JS::CompileOptions const&, unsigned short const*, unsigned int, JSString*, unsigned int, js::SourceCompressionToken*) /home/alan/git/B2G/gecko/js/src/frontend/BytecodeCompiler.cpp:193 (0x4254b566 libxul.so+0x1b92566)
   JS::Compile(JSContext*, JS::Handle, JS::CompileOptions, unsigned short const*, unsigned int) /home/alan/git/B2G/gecko/js/src/jsapi.cpp:5215 (0x42380e98 libxul.so+0x19c7e98)
   nsJSContext::CompileScript(unsigned short const*, int, nsIPrincipal*, char const*, unsigned int, unsigned int, nsScriptObjectHolder&, bool) /home/alan/git/B2G/gecko/dom/base/nsJSEnvironment.cpp:1621 (0x4135ad36 libxul.so+0x9a1d36)
   nsXULPrototypeScript::Compile(unsigned short const*, int, nsIURI*, unsigned int, nsIDocument*, nsIScriptGlobalObjectOwner*) /home/alan/git/B2G/gecko/content/xul/content/src/nsXULElement.cpp:2517 (0x4167d14a libxul.so+0xcc414a)
   nsXULDocument::OnStreamComplete(nsIStreamLoader*, nsISupports*, tag_nsresult, unsigned int, unsigned char const*) /home/alan/git/B2G/gecko/content/xul/document/src/nsXULDocument.cpp:3461 (0x4133f1a2 libxul.so+0x9861a2)
   nsStreamLoader::OnStopRequest(nsIRequest*, nsISupports*, tag_nsresult) /home/alan/git/B2G/gecko/netwerk/base/src/nsStreamLoader.cpp:95 (0x40cbe29a libxul.so+0x30529a)

 Reported at
   mozilla::dmd::Report(void const*) /home/alan/git/B2G/gecko/memory/replace/dmd/DMD.cpp:1741 (0x400fa672 libdmd.so+0x4672)
   JsMallocSizeOf /home/alan/git/B2G/gecko/js/xpconnect/src/XPCJSRuntime.cpp:1511 (0x41789e38 libxul.so+0xdd0e38)
   JSString::sizeOfExcludingThis(unsigned int (*)(void const*)) /home/alan/git/B2G/gecko/js/src/vm/String.cpp:71 (0x4254891a libxul.so+0x1b8f91a)
   JS::StatsCellCallback(JSRuntime*, void*, void*, JSGCTraceKind, unsigned int) /home/alan/git/B2G/gecko/js/src/jsmemorymetrics.cpp:173 (0x42443f38 libxul.so+0x1a8af38)
   js::IterateCellCallbackOp::operator()(js::gc::Cell*) /home/alan/git/B2G/gecko/js/src/jsgc.cpp:4788 (0x423e1b2c libxul.so+0x1a28b2c)
   void js::gc::ForEachArenaAndCell(JSCompartment*, js::gc::AllocKind, js::IterateArenaCallbackOp, js::IterateCellCallbackOp) /home/alan/git/B2G/gecko/js/src/jsgcinlines.h:385 (0x423e38e2 libxul.so+0x1a2a8e2)
   js::IterateCompartmentsArenasCells(JSRuntime*, void*, void (*)(JSRuntime*, void*, JSCompartment*), void (*)(JSRuntime*, void*, js::gc::Arena*, JSGCTraceKind, unsigned int), void (*)(JSRuntime*, void*, void*, JSGCTraceKind, unsigned int)) /home/alan/git/B2G/gecko/js/src/jsgc.cpp:4816 (0x423e1bf0 libxul.so+0x1a28bf0)
   JS::CollectRuntimeStats(JSRuntime*, JS::RuntimeStats*, JS::ObjectPrivateVisitor*) /home/alan/git/B2G/gecko/js/src/jsmemorymetrics.cpp:282 (0x4244432a libxul.so+0x1a8b32a)
   xpc::JSMemoryMultiReporter::CollectReports(nsDataHashtable*, nsIMemoryMultiReporterCallback*, nsISupports*) /home/alan/git/B2G/gecko/js/xpconnect/src/XPCJSRuntime.cpp:2089 (0x4178f3dc libxul.so+0xdd63dc)
   nsWindowMemoryReporter::CollectReports(nsIMemoryMultiReporterCallback*, nsISupports*) /home/alan/git/B2G/gecko/dom/base/nsWindowMemoryReporter.cpp:317 (0x413f7076 libxul.so+0xa3e076)
   mozilla::MemoryInfoDumper::DumpMemoryReportsToFileImpl(nsAString_internal const&) /home/alan/git/B2G/gecko/xpcom/base/MemoryInfoDumper.cpp:863 (0x41de0894 libxul.so+0x1427894)
   mozilla::MemoryInfoDumper::DumpMemoryReportsToFile(nsAString_internal const&, bool, bool) /home/alan/git/B2G/gecko/xpcom/base/MemoryInfoDumper.cpp:590 (0x41ddf2a4 libxul.so+0x14262a4)
   mozilla::(anonymous namespace)::DumpMemoryReportsRunnable::Run() /home/alan/git/B2G/gecko/xpcom/base/MemoryInfoDumper.cpp:73 (0x41dde000 libxul.so+0x1425000)
   nsThread::ProcessNextEvent(bool, bool*) /home/alan/git/B2G/gecko/xpcom/threads/nsThread.cpp:620 (0x41dc897c libxul.so+0x140f97c)
   NS_ProcessNextEvent_P(nsIThread*, bool) /home/alan/git/B2G/objdir-gecko-noopt-dmd/xpcom/build/nsThreadUtils.cpp:237 (0x41d826b2 libxul.so+0x13c96b2)
   mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) /home/alan/git/B2G/gecko/ipc/glue/MessagePump.cpp:79 (0x41b5534c libxul.so+0x119c34c)
   MessageLoop::RunInternal() /home/alan/git/B2G/gecko/ipc/chromium/src/base/message_loop.cc:217 (0x41e100dc libxul.so+0x14570dc)
   MessageLoop::RunHandler() /home/alan/git/B2G/gecko/ipc/chromium/src/base/message_loop.cc:210 (0x41e100ae libxul.so+0x14570ae)
   MessageLoop::Run() /home/alan/git/B2G/gecko/ipc/chromium/src/base/message_loop.cc:183 (0x41e10056 libxul.so+0x1457056)
   nsBaseAppShell::Run() /home/alan/git/B2G/gecko/widget/xpwidgets/nsBaseAppShell.cpp:165 (0x41a4f386 libxul.so+0x1096386)
   nsAppStartup::Run() /home/alan/git/B2G/gecko/toolkit/components/startup/nsAppStartup.cpp:290 (0x419014e4 libxul.so+0xf484e4)
   XREMain::XRE_mainRun() /home/alan/git/B2G/gecko/toolkit/xre/nsAppRunner.cpp:3794 (0x40c66abc libxul.so+0x2adabc)
   XREMain::XRE_main(int, char**, nsXREAppData const*) /home/alan/git/B2G/gecko/toolkit/xre/nsAppRunner.cpp:3860 (0x40c66cf0 libxul.so+0x2adcf0)
   XRE_main /home/alan/git/B2G/gecko/toolkit/xre/nsAppRunner.cpp:3935 (0x40c66e86 libxul.so+0x2ade86)

註:
[1] 更多關於 DMD 的資料
[2] 更多關於 memory reporter 以及 about:memory 的資料