repeated attribute changes lead to infinite rule tree growth

RESOLVED FIXED in mozilla1.4alpha



18 years ago
5 years ago


(Reporter: markushuebner, Assigned: dbaron)


(Depends on 1 bug, {memory-leak, perf, testcase})

Dependency tree / graph

Firefox Tracking Flags

(Not tracked)


(Whiteboard: [patch], )


(2 attachments, 7 obsolete attachments)



18 years ago
1. just go to
2. open the taskmanager
3. look at mozilla's memory usage - increasing about 300kb/sec !

memory usage will continue growing forever w/o never decreasing.

Verified using 0.9.7 and build 2001122803 on win2k and win-xp.

Comment 1

18 years ago
Confirming on Linux 2001122821. Memory usage growth stops after closing window.

Comment 2

18 years ago
Also on Linux 2001122608. If I stop close the window and reopen it, it takes a
while for the memory usage to grow.
OS: Windows 2000 → All

Comment 3

18 years ago
Posted file Reduced testcase
setAttribute("width") and ("height") seem to be the cause of this problem.
Does adding |var widthHeight;| in global scope help?
The main sources of increase are the following:

18675361 malloc
  17746654 PR_Malloc
    17453053 PL_ArenaAllocate
      17505210 FrameArena::AllocateFrame(unsigned int, void **)
        17505210 PresShell::AllocateFrame(unsigned int, void **)
          17496980 nsPresContext::AllocateFromShell(unsigned int, void **)
            5411225 nsResetStyleData::operator new(unsigned int, ...
            3962745 nsStyleBorder::operator new(unsigned int, nsIPresContext *)
            3168550 nsInheritedStyleData::operator new(unsigned int, ...
            1555470 nsRuleNode::operator new(unsigned int, nsIPresContext *)
            1390870 nsStyleDisplay::operator new(unsigned int, nsIPresContext *)
            921760 nsRuleList::operator new(unsigned int, nsIPresContext *)
            609020 nsStylePosition::operator new(unsigned int, nsIPresContext *)
            489685 nsShellISupportsKey::operator new(unsigned int, ...
    585728 /builds/trunk/obj/debug/dist/bin/
      585728 PL_HashTableRawAdd
        585728 nsHashtable::Put(nsHashKey *, void *)
          622496 nsRuleNode::Transition(nsIStyleRule *, nsRuleNode **)
            622496 nsRuleWalker::Forward(nsIStyleRule *)
  2116207 __builtin_new
    2016404 nsHTMLMappedAttributes::Clone(nsHTMLMappedAttributes **) const
      2016404 HTMLAttributesImpl::EnsureSingleMappedFor(nsIHTMLContent *, ...
        2016404 HTMLAttributesImpl::SetAttributeFor(nsIAtom *, ...
          2016404 HTMLStyleSheetImpl::SetAttributeFor(nsIAtom *, ...
            2016404 nsGenericHTMLElement::SetHTMLAttribute(nsIAtom *, ...
    1238368 HTMLAttribute::CopyHTMLAttributes(HTMLAttribute *, HTMLAttribute **)
      1238384 nsHTMLMappedAttributes::nsHTMLMappedAttributes(...
        1238384 nsHTMLMappedAttributes::Clone(nsHTMLMappedAttributes **) const
          1238384 HTMLAttributesImpl::EnsureSingleMappedFor(...
            1238384 HTMLAttributesImpl::SetAttributeFor(nsIAtom *, ...

(These numbers may be a bit skewed since my second log was truncated since my
disk filled up.)

Looks like rule tree growth, which is basically as-designed, since we want
reresolution to be fast, but perhaps we need to remove parts of the rule tree
when rules are removed?  I'm not really familiar with how the mapped attributes
stuff works, though.
Component: Browser-General → Style System

Comment 6

18 years ago
-- Does adding |var widthHeight;| in global scope help?


One possible solution (I think) would be to add a method |IsLive| to
|nsIStyleRule| and every time 1000 (or some large number) of rule nodes are
added to the rule tree, sweep the rule tree and remove all branches containing
nodes that are not live.  I *think* such a method could be implemented on
|nsHTMLMappedAttributes|, using its |mUseCount|.
Summary: Memory usage skyrocketing → repeated attribute changes lead to infinite rule tree growth


18 years ago
Blocks: 92580


18 years ago
Keywords: mozilla0.9.8


18 years ago
Keywords: mozilla0.9.9


18 years ago
Keywords: mozilla1.0


18 years ago
Keywords: mozilla1.0+


18 years ago
Keywords: mozilla1.0
The other thing such a solution would allow is keeping full rebuilds of the rule
tree rarer -- we could just do a sweep of the rule tree after a stylesheet
remove that would remove all rule nodes pointing to a rule node whose rule was
in a stylesheet that was no longer active.
...then again, that would cause a performance hit if a stylesheet were removed
and readded repeatedly.  But maybe that's rare enough that we don't care.
When we remove a rule node we'll need to clear the mapping in the style set
added for bug 99344.
Does anybody really think this should be fixed for 1.0?  I never did, since it
involves pretty major changes.
Priority: -- → P3
Target Milestone: --- → mozilla1.2alpha

Comment 12

17 years ago
*** Bug 142528 has been marked as a duplicate of this bug. ***

Comment 13

17 years ago
 I watch too many frames produced by the js.
   Edit-->Preferences-->Debug-->Event  and select show frames, clich OK

  Use the Reduced testcase, you will watch the frames' number become larger and
larger so fast.


17 years ago
Hardware: PC → All

Comment 14

17 years ago
  This error caused by the javascript in the html file. The IE have the same 

  -> won't fix
  I suggest to close it.

Comment 15

17 years ago
Using MSIE6 the memory consumption remains exactly the same all over the 
Using trunk build 2002062308 the memory consumptions goes up rapidly - as 
already said abour 300kb/sec.
This should be fixed at some point.

Comment 17

17 years ago
   If it is a bug really,it caused by reflow process, because the frame number 
increase continuely and not decrease. The "reduced testcase" draw a rectangle 
ceaselessly, so it can produce many many frames and take much memory. who can 
tell me the life cycle of a frame? I want to release the frames in time. 

   With the reduced testcase, The IE will take 100% cpu, but I takes little 
mem, I think it has a good garbage collector. If i can release the mem fastly, 
mozilla can work as IE.

   David Baron: could you give me some suggestions?
This has nothing to do with reflow, it has to do with the rule tree.  I
understand what it is and I'm planning to fix it one of these days.

Comment 19

17 years ago
Go to the URL and select 1 in the dropdown. The animation is soo awful that it
kind of reminds of bug 129953. Anyone else?

Using build 20020704 on Windows 2000

Comment 20

17 years ago
"Go to the URL and select 1 in the dropdown"
where is that ?

Comment 21

17 years ago
On this link:

Select 1 in the select box, if you dont see what I mean, then bring up the
windows task manager and then close it. 

Comment 22

17 years ago
I see heavy frame-drop offs on
see bug 157401.



17 years ago
Keywords: mozilla1.2
Target Milestone: mozilla1.2alpha → Future
Priority: P3 → P1


17 years ago
Keywords: nsbeta1
*** Bug 166298 has been marked as a duplicate of this bug. ***


17 years ago
Keywords: mozilla1.3


17 years ago
Keywords: mozilla1.2

Comment 25

17 years ago
The 3D Demo is now at
just 4 info :)

Target Milestone: Future → mozilla1.4alpha
I hacked up a patch for this that I'll attach shortly.  I haven't attempted to
compile it yet, and I won't until I'm able to land some of the things I have in
my existing compiling trees and free up some build space.

Note that there is a circular dependency between this patch and bug 171830 (see
the XXX comment in this patch).  I believe there would be some crashes if this
patch lands before bug 171830 because of stale info in the rule mappings table.
 Likewise, bug 171830 needs to land at the same time as this one or else we'll
have significant memory increases in significantly more cases.
Posted patch patch (untested) (obsolete) — Splinter Review
Untested.  Not even compiled.  Don't try this at home.	It won't compile.  And
if it does it will crash.

Like I said in the previous comment, I'll finish this once I clean out some of
my trees.
Posted patch patch (untested) (obsolete) — Splinter Review
Still untested, but a bunch of major errors now fixed.
Attachment #113465 - Attachment is obsolete: true
Before you test, add

mDependentBits &= ~NS_RULE_NODE_GC_MARK;

to Sweep() somewhere.

Looking pretty good otherwise...
Posted patch patch (untested) (obsolete) — Splinter Review
Yep.  I even said I'd do that in nsRuleNode.h.
Attachment #113496 - Attachment is obsolete: true
Posted patch patch (untested) (obsolete) — Splinter Review
Return too.
Attachment #113514 - Attachment is obsolete: true
Posted patch patch (obsolete) — Splinter Review
This compiles, runs, and prevents memory use from increasing while displaying
Attachment #113515 - Attachment is obsolete: true
Whiteboard: [patch]
Posted patch patch (obsolete) — Splinter Review
merged to tip
Attachment #114148 - Attachment is obsolete: true
Posted patch patch (obsolete) — Splinter Review
This allows for the fact that there can be multiple style contexts without a
parent.  I still saw one crash, but I can't reproduce it.  (I also have a
version merged with bz's patch to bug 171830.)
Attachment #115396 - Attachment is obsolete: true

Comment 35

17 years ago
*** Bug 195408 has been marked as a duplicate of this bug. ***
David, are you happy enough with that patch that you want reviews for it?  Or
are you still testing?
Well, I was playing around with a tree that had it and bug 171830 merged in a
single tree.  I crashed.  I looked at the stack quickly in the debugger, thought
I knew what was going on, quit the debugger, went to fix the code, and the
problem I thought was there didn't exist.  And I haven't been able to reproduce
the crash since.

I guess there's a chance the problem could be unrelated, but it seems unlikely.
 I guess you could review, though, and hopefully we'll find the crash later?
Comment on attachment 115409 [details] [diff] [review]


OK, so Sweep() will Destroy() the rulenode and return PR_TRUE if it was

>+        if ((*children)->mRuleNode->Sweep()) {
>+          // This rule node was destroyed, so remove this entry, and
>+          // implicitly advance by making *children point to the next
>+          // entry.
>+          nsRuleList *todestroy = *children;
>+          *children = todestroy->mNext;
>+          todestroy->mNext = nsnull;
>+          todestroy->Destroy(mPresContext);

and this will call nsRuleList::Destroy which will turn around and call
Destroy() on its mRuleNode _again_ and then wipe out the rest of the list
(neither of which is desirable as far as I can tell).  Shouldn't that be a call
to DestroySelf instead?  Like:

  *children = (*children)->DestroySelf(mPresContext);

instead of those four lines of code?  (Now why didn't I read the definition of
Destroy() the forst time I read this patch?  <sigh>)

This seems like a reasonable candidate for that crash you were seeing.....

>+StyleSetImpl::NotifyStyleContextDestroyed(nsIPresContext* aPresContext,
>+                                          nsStyleContext* aStyleContext)

This should check mInShutdown and return without doing anything if that's set,

Looks pretty good other than those two issues.
Posted patch patchSplinter Review
I haven't tested this yet, but it fixes the problems bz pointed out, plus a
missing return and the removal of the comment that won't be needed once bug
171830 lands.
Attachment #115409 - Attachment is obsolete: true
Attachment #116400 - Flags: superreview?(bzbarsky)
Attachment #116400 - Flags: review?(bzbarsky)
Comment on attachment 116400 [details] [diff] [review]

Good catch on the return... (and on clearing mRoots when we start shutting
down).	r+sr=bzbarsky
Attachment #116400 - Flags: superreview?(bzbarsky)
Attachment #116400 - Flags: superreview+
Attachment #116400 - Flags: review?(bzbarsky)
Attachment #116400 - Flags: review+
Fix checked in to trunk, 2003-03-06 11:14 PST (with bustage fix at 12:16 PST).
Closed: 17 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.