Buffer allocator ends up with too many partially used chunks
Categories
(Core :: JavaScript: GC, task, P1)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox153 | --- | fixed |
People
(Reporter: jonco, Assigned: jonco)
References
(Blocks 1 open bug)
Details
Attachments
(2 external files)
After surfacing more buffer allocator information in about:memory I noticed that there can be a lot of almost empty chunks. We do give unused space back to the OS by decommitting it but this does waste virtual address space and increases overhead in the buffer allocator.
I investigated this and found that most of these chunks are being allocated during incremental marking. This indicates it's due to the way the buffer allocator works where chunks that will need sweeping for major GC are moved to a separate list at the start of GC and subsequent allocations cause new chunks to be allocated. It seems this is happening pretty frequently and these chunks are piling up.
| Assignee | ||
Comment 1•5 months ago
|
||
This was a convenient way to get this mark state for free but it interacts with
adding a marking barrier in the next patch. Instead we can store this
explicitly in the metadata itself.
This also has the advantage that we can make it properly atomic and avoid the
benign but wasteful possibility to two parallel marking threads marking the
contents of the buffer at the same time.
| Assignee | ||
Comment 2•5 months ago
|
||
Currently the buffer allocator moves all chunks out of the current allocation
lists to a sweep list at the start of a major collection and they are not used
for allocation after that point until they have been swept. This is because it
doesn't support allocating from chunks while they are being swepti, and because
it's easiest to work out what need to be swept at the start of collection
rather than later at the start of sweeping. However this means that allocations
that happen during an incremental collection cause new chunks to allocated.
Since this can happen on every collection we can end up with many under used
chunks.
One possible solution would be to allow allocation and sweeping to happen
concurrently but making this work correctly without races is complicated
and a large change to the current design.
I investigated moving chunks to the sweep list at the start of sweeping instead
of at the start of collection but this was complicated by interactions with
minor collection. At the start of major collection we arrange that a minor
collection is started and we will wait for it to finish before major sweeping
starts. However subsequent minor collections can happen after that point and
can be ongoing at the start of sweeping. Waiting for them can slow down
collections and cause performance impact on benchmarks. Without doing that this
approach proved complicated to get working.
Leaving some mostly empty chunks unswept so they could be used for allocation
seemed like a good heuristic. But the problem was knowing how many to leave to
be effective and still sweep as much as possible.
Finally I came up with the solution here. Everything is moved to the sweep list
at the start of collection as normal. Then, if we later need to allocate during
marking we can steal chunks back from the sweep list and used them from
allocation. These chunks will not be swept in the current collection. This
only happens for chunks that are mostly empty (they must have a free region >=
1/2 chunk in size). The sweep list is arranged so that it is ordered by the
size of largest free region. This approximates free space well enough so that
mostly empty chunks can be used.
Updated•5 months ago
|
Comment 4•5 months ago
|
||
| bugherder | ||
https://hg.mozilla.org/mozilla-central/rev/eafe0f194ae1
https://hg.mozilla.org/mozilla-central/rev/a15cde96683b
Description
•