allocatePinned can lead to very bad fragmentation due to the nursery
I have been observing a program which has about 4mb of live data but retains over 700 megablocks.
The memInventory
indicated that the majority of blocks were being retained in the free list. I dumped out the contents of the free list and could see a lot of megabocks which were 251/252 free. Then I dumped out the contents of the nursery as well and checked which mblock each nursery block was in. You can see that the nursery has ended up consisting of a small number of blocks from a large number of different megablocks.
[("free",249),("nurs",3)]
[("free",249),("nurs",3)]
[("free",249),("nurs",3)]
[("free",249),("nurs",3)]
[("free",249),("nurs",3)]
[("free",249),("nurs",3)]
[("free",249),("nurs",3)]
[("free",249),("nurs",3)]
[("free",249),("nurs",3)]
[("free",249),("nurs",3)]
.... repeated 500 times
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
[("free",251),("nurs",1)]
The reason we end up with this problem in the first place is because the allocatePinned
function will steal 1/2 blocks from the nursery. This leads to a lot of resize operations just increasing the size of the nursery by 1/2 blocks which just get random blocks from the free list.
- Freshly reallocate the nursery periodically (expensive if we do it every time)
- Refuse to resize the nursery by a small amount, so to make sure that you upper bound the number of mblocks which could participate in the nursery.
- Don't steal nursery blocks in allocatePinned (You could still get fragmentation issues here but it will be nowhere near as bad)
This is what the free list looks like after stopping allocatePinned
from stealing blocks from the nursery. No fragmentation!
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("nurs",252)]
[("free",38),("gen1",189)]
220:F(48):G1(44):N(128)
[("free",70),("gen1",161)]
[("free",71),("gen1",157)]
[("free",90),("gen1",48)]
[("free",134),("gen1",116)]
[("free",147),("gen1",98)]
[("free",188),("gen1",60)]
[("free",194),("gen1",37)]
[("free",199),("gen1",52)]
[("free",203),("gen1",39)]
[("free",219),("gen1",31)]
[("free",220),("gen1",31)]
[("free",222),("gen1",29)]
[("free",223),("gen1",28)]
[("free",224),("gen1",27)]
[("free",225),("gen1",26)]
[("free",227),("gen1",16)]
[("free",231),("gen1",20)]
[("free",233),("gen1",18)]
[("free",234)]
[("free",235),("gen1",16)]
[("free",237),("gen1",14)]
[("free",237),("gen1",14)]
[("free",238),("gen1",13)]
[("free",239)]
[("free",242),("gen1",9)]
[("free",242)]
[("free",244),("gen1",8)]
[("free",246),("gen1",5)]
[("free",246),("gen1",5)]
[("free",247)]
[("free",247)]
[("free",248)]
[("free",248)]
[("free",248)]
[("free",250)]
[("free",250)]
[("free",250)]
[("free",250)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]
[("free",251)]