Changeset 133119 in webkit


Ignore:
Timestamp:
Oct 31, 2012, 8:21:02 PM (13 years ago)
Author:
cevans@google.com
Message:

RenderArena has a memory leak and poor efficiency
https://bugs.webkit.org/show_bug.cgi?id=100893

Reviewed by Eric Seidel.

1) Avoid memory leak that persists for the Document lifetime by
increasing recycled size buckets up to 1024. It was previously 400,
and sizeof(RenderNamedFlowThread) / sizeof(RenderSVGText) both blew this
quota. An assert was added to prevent this happening again.

2) Fix the size of the recyled size bucket array on 64-bit. We only
need 8 byte granularity on 64-bit, but we had 4.

3) Try and pass power-of-two sizes to the underlying malloc() call, so
that we're space efficient. We now take Arena metadata into account.

4) Double the default RenderArena size allocation to 8192 bytes. Even
for a render of a trivial text file, 4096 bytes is not enough to prevent
extra calls into the underlying malloc() for more arena pool.

  • rendering/RenderArena.cpp:

(WebCore::RenderArena::RenderArena): Adjust arena size so that we pass on the page-sized multiple to the underlying malloc() implementation.
(WebCore::RenderArena::allocate):
(WebCore::RenderArena::free): Assert that the allocation size is handled by our recycling buckets.

  • rendering/RenderArena.h:

(WebCore): Maintain free buckets up to 1024 bytes to avoid memory leak.
(RenderArena): Double the default allocation size and handle 64-bit systems more efficiently.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r133113 r133119  
     12012-10-31  Chris Evans  <cevans@google.com>
     2
     3        RenderArena has a memory leak and poor efficiency
     4        https://bugs.webkit.org/show_bug.cgi?id=100893
     5
     6        Reviewed by Eric Seidel.
     7
     8        1) Avoid memory leak that persists for the Document lifetime by
     9        increasing recycled size buckets up to 1024. It was previously 400,
     10        and sizeof(RenderNamedFlowThread) / sizeof(RenderSVGText) both blew this
     11        quota. An assert was added to prevent this happening again.
     12
     13        2) Fix the size of the recyled size bucket array on 64-bit. We only
     14        need 8 byte granularity on 64-bit, but we had 4.
     15
     16        3) Try and pass power-of-two sizes to the underlying malloc() call, so
     17        that we're space efficient. We now take Arena metadata into account.
     18
     19        4) Double the default RenderArena size allocation to 8192 bytes. Even
     20        for a render of a trivial text file, 4096 bytes is not enough to prevent
     21        extra calls into the underlying malloc() for more arena pool.
     22
     23        * rendering/RenderArena.cpp:
     24        (WebCore::RenderArena::RenderArena): Adjust arena size so that we pass on the page-sized multiple to the underlying malloc() implementation.
     25        (WebCore::RenderArena::allocate):
     26        (WebCore::RenderArena::free): Assert that the allocation size is handled by our recycling buckets.
     27        * rendering/RenderArena.h:
     28        (WebCore): Maintain free buckets up to 1024 bytes to avoid memory leak.
     29        (RenderArena): Double the default allocation size and handle 64-bit systems more efficiently.
     30
    1312012-10-31  Adam Barth  <abarth@webkit.org>
    232
  • trunk/Source/WebCore/rendering/RenderArena.cpp

    r132970 r133119  
    7171    , m_totalAllocated(0)
    7272{
     73    ASSERT(arenaSize > sizeof(Arena) + ARENA_ALIGN_MASK);
     74    // The underlying Arena class allocates some metadata on top of our
     75    // requested size. Factor this in so that we can get perfect power-of-two
     76    // allocation sizes passed to the underlying malloc() call.
     77    arenaSize -= (sizeof(Arena) + ARENA_ALIGN_MASK);
    7378    // Initialize the arena pool
    7479    INIT_ARENA_POOL(&m_pool, "RenderArena", arenaSize);
     
    98103void* RenderArena::allocate(size_t size)
    99104{
     105    ASSERT(size <= gMaxRecycledSize - 32);
    100106    m_totalSize += size;
    101107
     
    112118    return static_cast<char*>(block) + debugHeaderSize;
    113119#else
    114     void* result = 0;
    115 
    116120    // Ensure we have correct alignment for pointers.  Important for Tru64
    117121    size = ROUNDUP(size, sizeof(void*));
    118122
    119     // Check recyclers first
    120     if (size < gMaxRecycledSize) {
    121         const size_t index = size >> 2;
     123    const size_t index = size >> kRecyclerShift;
    122124
    123         result = m_recyclers[index];
    124         if (result) {
    125             // Need to move to the next object
    126             void* next = MaskPtr(*((void**)result), m_mask);
    127             m_recyclers[index] = next;
    128         }
     125    void* result = m_recyclers[index];
     126    if (result) {
     127        // Need to move to the next object
     128        void* next = MaskPtr(*((void**)result), m_mask);
     129        m_recyclers[index] = next;
    129130    }
    130131
     
    142143void RenderArena::free(size_t size, void* ptr)
    143144{
     145    ASSERT(size <= gMaxRecycledSize - 32);
    144146    m_totalSize -= size;
    145147
     
    159161    size = ROUNDUP(size, sizeof(void*));
    160162
    161     // See if it's a size that we recycle
    162     if (size < gMaxRecycledSize) {
    163         const size_t index = size >> 2;
    164         void* currentTop = m_recyclers[index];
    165         m_recyclers[index] = ptr;
    166         *((void**)ptr) = MaskPtr(currentTop, m_mask);
    167     }
     163    const size_t index = size >> kRecyclerShift;
     164    void* currentTop = m_recyclers[index];
     165    m_recyclers[index] = ptr;
     166    *((void**)ptr) = MaskPtr(currentTop, m_mask);
    168167#endif
    169168}
  • trunk/Source/WebCore/rendering/RenderArena.h

    r132970 r133119  
    4242namespace WebCore {
    4343
    44 static const size_t gMaxRecycledSize = 400;
     44static const size_t gMaxRecycledSize = 1024;
    4545
    4646class RenderArena {
    4747    WTF_MAKE_NONCOPYABLE(RenderArena); WTF_MAKE_FAST_ALLOCATED;
    4848public:
    49     RenderArena(unsigned arenaSize = 4096);
     49    RenderArena(unsigned arenaSize = 8192);
    5050    ~RenderArena();
    5151
     
    6363    // The mask used to secure the recycled freelist pointers.
    6464    uintptr_t m_mask;
    65     // The recycler array is sparse with the indices being multiples of 4,
    66     // i.e., 0, 4, 8, 12, 16, 20, ...
    67     void* m_recyclers[gMaxRecycledSize >> 2];
     65    // The recycler array is sparse with the indices being multiples of the
     66    // rounding size, sizeof(void*), i.e., 0, 4, 8, 12, 16, 20, ... on 32-bit.
     67    static const size_t kRecyclerShift = (sizeof(void*) == 8) ? 3 : 2;
     68    void* m_recyclers[gMaxRecycledSize >> kRecyclerShift];
    6869
    6970    size_t m_totalSize;
Note: See TracChangeset for help on using the changeset viewer.