Platform/Memory Reporting: Difference between revisions

Jump to navigation Jump to search
Line 110: Line 110:
=== An Example Involving Inheritance ===
=== An Example Involving Inheritance ===


Things are a little trickier when inheritance is involved.  Every sub-class needs to have its own implementation of <tt>SizeOfExcludingThis</tt>.  In contrast, if <tt>SizeOfExcludingThis</tt> is present, only a single <tt>SizeOfIncludingThis</tt> is needed for the whole class hierarchy.  An example:
Things are a little trickier when inheritance is involved.  An example:


   class B {
   class B {
     virtual foo() { ... }
     virtual foo() { ... }
    
    
     virtual NS_MUST_OVERRIDE size_t
     virtual size_t
       SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
       SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
     {
     {
Line 126: Line 126:
         return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
         return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     }
     }
   
    // data members
   };
   };
    
    
Line 131: Line 133:
     virtual foo() { ... }
     virtual foo() { ... }
    
    
     virtual NS_MUST_OVERRIDE size_t
     virtual size_t
       SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE
       SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE
     {
     {
Line 138: Line 140:
         return n;
         return n;
     }
     }
   
    virtual size_t
      SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE
    {
        return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    }
   
    // data members
   };
   };


Things to note:
Things to note about <tt>SizeOfExcludingThis</tt>.
 
* If <tt>D</tt> has data members that point to other objects, then <tt>D::SizeOfExcludingThis</tt> must override <tt>B::SizeOfExcludingThis</tt>.  Otherwise, if we have a <tt>B*</tt> pointer that actually points to a <tt>D</tt> object, we'll end up calling <tt>B::SizeOfExcludingThis</tt> instead of <tt>D::SizeOfExcludingThis</tt>, and thus we'll fail to measure any objects that <tt>D</tt>'s fields point to.  <tt>D::SizeOfExcludingThis</tt> must also call <tt>B::SizeOfExcludingThis</tt>, to ensure that any objects pointed to by fields inherited from <tt>B</tt> are measured.


* <tt>D::SizeOfExcludingThis</tt> must override <tt>B::SizeOfExcludingThis</tt>.  If it doesn't, if we have a <tt>B*</tt> pointer that actually points to a <tt>D</tt> object, we'll end up calling <tt>B::SizeOfExcludingThis</tt> instead of <tt>D::SizeOfExcludingThis</tt>, and thus we'll fail to measure any objects that <tt>D</tt>'s fields point to.
* However, if <tt>D</tt> does not have any of its own fields that point to other objects, then <tt>D::SizeOfExcludingThis</tt> is not necessary.


* <tt>D::SizeOfExcludingThis</tt> must also call <tt>B::SizeOfExcludingThis</tt>, to ensure that any objects pointed to by fields inherited from <tt>B</tt> are measured.
* Alternatively, if <tt>D</tt> does have fields that point to other objects but you don't want to measure them because they're insignificant, then <tt>D::SizeOfExcludingThis</tt> is again not necessary.  But it's a good idea to add a comment indicating this decision not to measure, and the names of the unmeasured fields.  The obvious place for this comment is within <tt>D</tt>, but if <tt>B</tt> has many sub-classes like that, it might be easier to put the comment above <tt>B::SizeOfIncludingThis</tt>.


* <tt>D::SizeOfIncludingThis</tt> is inherited from <tt>B</tt>.  The <tt>SizeOfExcludingThis()</tt> call within will be dispatched to <tt>D::SizeOfExcludingThis</tt> when appropriate (because <tt>B::SizeOfIncludingThis</tt> is <tt>virtual</tt>) which is what we want.
Things to note about <tt>SizeOfIncludingThis</tt>.


* The <tt>NS_MUST_OVERRIDE</tt> is an annotation that indicates that this function must be overridden by any sub-classesIt's used by some static analysis toolsCurrently these tools aren't running, but they might in the future, and it's a useful piece of documentation.
* <tt>D::SizeOfIncludingThis</tt> is identical to <tt>B::SizeOfIncludingThis</tt>.  You might think that <tt>D</tt> could just inherit <tt>SizeOfIncludingThis</tt> from <tt>B</tt>In some cases this works, but there's a lot of C++ subtlety involving the <tt>aMallocSizeOf(this)</tt> and whether <tt>this</tt> actually points to the start of the allocated object or somewhere in it's middle.  This is doubly true if <tt>D</tt> features multiple inheritanceSo, if in doubt, define <tt>D::SizeOfIncludingThis</tt> and you should be safe.


* The <tt>MOZ_OVERRIDE</tt> annotation says that <tt>D::SizeOfExcludingThis</tt> overrides the corresponding function in <tt>B</tt>.  On supporting compilers it gets expanded to the <tt>override</tt> keyword.  It helps prevent accidentally having small differences in the function signatures (e.g. forgetting a <tt>const</tt>) that prevent the overriding from happening.
* The <tt>MOZ_OVERRIDE</tt> annotations say that <tt>D</tt>'s methods override the corresponding methods in <tt>B</tt>.  On supporting compilers it gets expanded to the <tt>override</tt> keyword.  It helps prevent accidentally having small differences in the function signatures (e.g. forgetting a <tt>const</tt>) that prevent the overriding from happening.


=== Other Considerations ===
=== Other Considerations ===
Confirmed users
1,345

edits

Navigation menu