Closed Bug 790695 Opened 12 years ago Closed 3 years ago

Calling DOMParser.parseFromString 100k times leaves 100MB of heap-unclassified memory

Categories

(Core :: DOM: HTML Parser, defect, P5)

x86
macOS
defect

Tracking

()

RESOLVED WORKSFORME

People

(Reporter: florian, Unassigned)

References

Details

(Keywords: memory-leak, Whiteboard: [MemShrink:P2])

I see heap-unclassified in about:memory increase by about 100MB after executing this line in the error console and pressing "Minimize memory usage":

var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser); for (var i = 0; i < 100000; ++i) parser.parseFromString("foo", "text/html");

Note: be sure to have the gecko profiler or any add-on using a Jetpack older than 1.10 disabled, otherwise bug 769483 will be in your way.

Note2: Executing this 100k times seems excessive, but Thunderbird actually calls parseFromString once for each received IM or tweet, so it can be called thousands of times within hours (or minutes if the user is in very busy IRC channels).
Adding [MemShrink] in the whiteboard and CC'ing njn, in case it's something that the memshrink team cares about.

Here are the 3 largest unreported block groups in DMD's output after running the testcase in comment 0:

Unreported: 4,761 blocks in block group 1 of 1,862
 58,503,168 bytes (39,116,376 requested / 19,386,792 slop)
 36,69% of the heap (36,69% cumulative);  44,85% of unreported (44,85% cumulative)
 Allocated at
   0_asl_msg_test_expression (in libsystem_c.dylib) + 83
   0_asl_msg_new_key_val_op (in libsystem_c.dylib) + 571
      0L_ArenaAllocate (plarena.c:200, in libplds4.dylib)
      0nsFixedSizeAllocator::Alloc(unsigned long) (in XUL) (nsFixedSizeAllocator.cpp:95)
      0nsNodeInfo::Create(nsIAtom*, nsIAtom*, int, unsigned short, nsIAtom*, nsNodeInfoManager*) (in XUL) (nsNodeInfo.cpp:64)
      0nsNodeInfoManager::GetNodeInfo(nsIAtom*, nsIAtom*, int, unsigned short, nsIAtom*) (in XUL) (nsNodeInfoManager.cpp:225)
      0nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor*, nsIContent**) (in XUL) (nsHtml5TreeOperation.cpp:340)
      0sHtml5TreeOpExecutor::FlushDocumentWrite() (nsHtml5TreeOpExecutor.cpp:653, in XUL)
      0nsHtml5StringParser::Tokenize(nsAString_internal const&, nsIDocument*, bool) (in XUL) (nsAutoPtr.h:124)
      0nsHtml5StringParser::ParseDocument(nsAString_internal const&, nsIDocument*, bool) (in XUL) (nsHtml5StringParser.cpp:88)
      0nsContentUtils::ParseDocumentHTML(nsAString_internal const&, nsIDocument*, bool) (in XUL) (AutoRestore.h:40)
      0nsDOMParser::ParseFromString(nsAString_internal const&, char const*, nsIDOMDocument**) (in XUL) (nsDOMParser.cpp:93)
      0nsDOMParser::ParseFromString(nsAString_internal const&, mozilla::dom::SupportedTypeValues::valuelist, mozilla::ErrorResult&) (in XUL) (nsDOMParser.cpp:50)
      0mozilla::dom::DOMParserBinding::parseFromString(JSContext*, JS::Handle<JSObject*>, nsDOMParser*, unsigned int, JS::Value*) (in XUL) (DOMParserBinding.cpp:70)
      0mozilla::dom::DOMParserBinding::genericMethod(JSContext*, unsigned int, JS::Value*) (in XUL) (DOMParserBinding.cpp:398)

Unreported: 1,587 blocks in block group 2 of 1,862
 19,501,056 bytes (13,038,792 requested / 6,462,264 slop)
 12,23% of the heap (48,92% cumulative);  14,95% of unreported (59,79% cumulative)
 Allocated at
   0_asl_msg_test_expression (in libsystem_c.dylib) + 83
   0_asl_msg_new_key_val_op (in libsystem_c.dylib) + 571
      0L_ArenaAllocate (plarena.c:200, in libplds4.dylib)
      0nsFixedSizeAllocator::Alloc(unsigned long) (in XUL) (nsFixedSizeAllocator.cpp:95)
      0nsNodeInfo::Create(nsIAtom*, nsIAtom*, int, unsigned short, nsIAtom*, nsNodeInfoManager*) (in XUL) (nsNodeInfo.cpp:64)
      0nsNodeInfoManager::GetNodeInfo(nsIAtom*, nsIAtom*, int, unsigned short, nsIAtom*) (in XUL) (nsNodeInfoManager.cpp:225)
      0sNodeInfoManager::GetTextNodeInfo() (nsNodeInfoManager.cpp:316, in XUL)
      0NS_NewTextNode(nsIContent**, nsNodeInfoManager*) (in XUL) (nsTextNode.cpp:100)
      0nsHtml5TreeOperation::AppendText(unsigned short const*, unsigned int, nsIContent*, nsHtml5TreeOpExecutor*) (in XUL) (nsCOMPtr.h:764)
      0nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor*, nsIContent**) (in XUL) (nsHtml5TreeOperation.cpp:511)
      0sHtml5TreeOpExecutor::FlushDocumentWrite() (nsHtml5TreeOpExecutor.cpp:653, in XUL)
      0nsHtml5StringParser::Tokenize(nsAString_internal const&, nsIDocument*, bool) (in XUL) (nsAutoPtr.h:124)
      0nsHtml5StringParser::ParseDocument(nsAString_internal const&, nsIDocument*, bool) (in XUL) (nsHtml5StringParser.cpp:88)
      0nsContentUtils::ParseDocumentHTML(nsAString_internal const&, nsIDocument*, bool) (in XUL) (AutoRestore.h:40)
      0nsDOMParser::ParseFromString(nsAString_internal const&, char const*, nsIDOMDocument**) (in XUL) (nsDOMParser.cpp:93)
      0nsDOMParser::ParseFromString(nsAString_internal const&, mozilla::dom::SupportedTypeValues::valuelist, mozilla::ErrorResult&) (in XUL) (nsDOMParser.cpp:50)
      0mozilla::dom::DOMParserBinding::parseFromString(JSContext*, JS::Handle<JSObject*>, nsDOMParser*, unsigned int, JS::Value*) (in XUL) (DOMParserBinding.cpp:70)
      0mozilla::dom::DOMParserBinding::genericMethod(JSContext*, unsigned int, JS::Value*) (in XUL) (DOMParserBinding.cpp:398)

Unreported: 1,587 blocks in block group 3 of 1,862
 19,501,056 bytes (13,038,792 requested / 6,462,264 slop)
 12,23% of the heap (61,15% cumulative);  14,95% of unreported (74,74% cumulative)
 Allocated at
   0_asl_msg_test_expression (in libsystem_c.dylib) + 83
   0_asl_msg_new_key_val_op (in libsystem_c.dylib) + 571
      0L_ArenaAllocate (plarena.c:200, in libplds4.dylib)
      0nsFixedSizeAllocator::Alloc(unsigned long) (in XUL) (nsFixedSizeAllocator.cpp:95)
      0nsNodeInfo::Create(nsIAtom*, nsIAtom*, int, unsigned short, nsIAtom*, nsNodeInfoManager*) (in XUL) (nsNodeInfo.cpp:64)
      0nsNodeInfoManager::GetNodeInfo(nsIAtom*, nsIAtom*, int, unsigned short, nsIAtom*) (in XUL) (nsNodeInfoManager.cpp:225)
      0sNodeInfoManager::GetDocumentNodeInfo() (nsNodeInfoManager.cpp:347, in XUL)
      0sDocument::Init() (nsDocument.cpp:1807, in XUL)
      0sHTMLDocument::Init() (nsHTMLDocument.cpp:257, in XUL)
      0NS_NewHTMLDocument(nsIDocument**, bool) (in XUL) (nsHTMLDocument.cpp:181)
      0NS_NewDOMDocument(nsIDOMDocument**, nsAString_internal const&, nsAString_internal const&, nsIDOMDocumentType*, nsIURI*, nsIURI*, nsIPrincipal*, bool, nsIScriptGlobalObject*, DocumentFlavor) (in XUL) (nsXMLDocument.cpp:87)
      0nsDOMParser::SetUpDocument(DocumentFlavor, nsIDOMDocument**) (in XUL) (nsDOMParser.cpp:508)
      0nsDOMParser::ParseFromString(nsAString_internal const&, char const*, nsIDOMDocument**) (in XUL) (nsDOMParser.cpp:77)
      0nsDOMParser::ParseFromString(nsAString_internal const&, mozilla::dom::SupportedTypeValues::valuelist, mozilla::ErrorResult&) (in XUL) (nsDOMParser.cpp:50)
      0mozilla::dom::DOMParserBinding::parseFromString(JSContext*, JS::Handle<JSObject*>, nsDOMParser*, unsigned int, JS::Value*) (in XUL) (DOMParserBinding.cpp:70)
      0mozilla::dom::DOMParserBinding::genericMethod(JSContext*, unsigned int, JS::Value*) (in XUL) (DOMParserBinding.cpp:398)
Whiteboard: [MemShrink]
Thanks for running DMD!

bz, any ideas if the existing DOM reporters should catch this?


> 0mozilla::dom::DOMParserBinding::genericMethod(JSContext*, unsigned int, JS::Value*) (in XUL) (DOMParserBinding.cpp:398)

BTW, I think you must have an oldish version of DMD (e.g. one from just after it landed).  If you update, the '0' at the start should go away and the PC will be printed at the end of each line.
Does this memory go away if you minimize memory usage?
(In reply to Justin Lebar [:jlebar] from comment #3)
> Does this memory go away if you minimize memory usage?

Yes and no. After running the test case, about:memory shows 1GB of heap-unclassified. After clicking "minimize memory usage", 100MB is left (in addition to the about 25MB that were already there just after starting Firefox).

The report from DMD in comment 1 was after clicking "minimize memory usage", and I think the 3 block groups I pasted in comment 1 are what takes most of the 100MB that stay around forever.
The nodeinfo manager (and the nodeinfos it contains) should probably be reported as part of the document.
(In reply to Peter Van der Beken [:peterv] from comment #5)
> The nodeinfo manager (and the nodeinfos it contains) should probably be
> reported as part of the document.

I'm not completely sure, but I don't think documents created through DOMParser.parseFromString are visible in about:memory.
Whiteboard: [MemShrink] → [MemShrink:P2]

Bulk-downgrade of unassigned, >=3 years untouched DOM/Storage bug's priority.

If you have reason to believe this is wrong, please write a comment and ni :jstutte.

Severity: normal → S4
Priority: -- → P5
Depends on: 1690905

Florian, with bug 1690905 fixed before the weekend is this problem now gone for you?

Flags: needinfo?(florian)

Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser); should now be replaced with new DOMParser() to test this.

When I run this, I still see a large heap unclassified value (1+GB) for the process where I ran the code, but nothing big remains after clicking "Minimize memory usage".

Status: NEW → RESOLVED
Closed: 3 years ago
Flags: needinfo?(florian)
Resolution: --- → WORKSFORME
You need to log in before you can comment on or make changes to this bug.