forked frompostgres/postgres
- Notifications
You must be signed in to change notification settings - Fork6
Commitc6e0fe1
committed
Improve performance of and reduce overheads of memory management
Whenever we palloc a chunk of memory, traditionally, we prefix thereturned pointer with a pointer to the memory context to which the chunkbelongs. This is required so that we're able to easily determine theowning context when performing operations such as pfree() and repalloc().For the AllocSet context, prior to this commit we additionally prefixedthe pointer to the owning context with the size of the chunk. This madethe header 16 bytes in size. This 16-byte overhead was required for allAllocSet allocations regardless of the allocation size.For the generation context, the problem was worse; in addition to thepointer to the owning context and chunk size, we also stored a pointer tothe owning block so that we could track the number of freed chunks on ablock.The slab allocator had a 16-byte chunk header.The changes being made here reduce the chunk header size down to just 8bytes for all 3 of our memory context types. For small to medium sizedallocations, this significantly increases the number of chunks that we canfit on a given block which results in much more efficient use of memory.Additionally, this commit completely changes the rule that pointers topalloc'd memory must be directly prefixed by a pointer to the owningmemory context and instead, we now insist that they're directly prefixedby an 8-byte value where the least significant 3-bits are set to a valueto indicate which type of memory context the pointer belongs to. Usingthose 3 bits as an index (known as MemoryContextMethodID) to a new arraywhich stores the methods for each memory context type, we're now able topass the pointer given to functions such as pfree() and repalloc() to thefunction specific to that context implementation to allow them to devisetheir own methods of finding the memory context which owns the givenallocated chunk of memory.The reason we're able to reduce the chunk header down to just 8 bytes isbecause of the way we make use of the remaining 61 bits of the required8-byte chunk header. Here we also implement a general-purpose MemoryChunkstruct which makes use of those 61 remaining bits to allow the storage ofa 30-bit value which the MemoryContext is free to use as it pleases, andalso the number of bytes which must be subtracted from the chunk to get areference to the block that the chunk is stored on (also 30 bits). The 1additional remaining bit is to denote if the chunk is an "external" chunkor not. External here means that the chunk header does not store the30-bit value or the block offset. The MemoryContext can use theseexternal chunks at any time, but must use them if any of the two 30-bitfields are not large enough for the value(s) that need to be stored inthem. When the chunk is marked as external, it is up to the MemoryContextto devise its own means to determine the block offset.Using 3-bits for the MemoryContextMethodID does mean we're limitingourselves to only having a maximum of 8 different memory context types.We could reduce the bit space for the 30-bit value a little to make wayfor more than 3 bits, but it seems like it might be better to do that onlyif we ever need more than 8 context types. This would only be a problemif some future memory context type which does not use MemoryChunk reallycouldn't give up any of the 61 remaining bits in the chunk header.With this MemoryChunk, each of our 3 memory context types can quicklyobtain a reference to the block any given chunk is located on. AllocSetis able to find the context to which the chunk is owned, by firstobtaining a reference to the block by subtracting the block offset as isstored in the 'hdrmask' field and then referencing the block's 'aset'field. The Generation context uses the same method, but GenerationBlockdid not have a field pointing back to the owning context, so one is addedby this commit.In aset.c and generation.c, all allocations larger than allocChunkLimitare stored on dedicated blocks. When there's just a single chunk on ablock like this, it's easy to find the block from the chunk, we justsubtract the size of the block header from the chunk pointer. The size ofthese chunks is also known as we store the endptr on the block, so we canjust subtract the pointer to the allocated memory from that. Because wecan easily find the owning block and the size of the chunk for thesededicated blocks, we just always use external chunks for allocation sizeslarger than allocChunkLimit. For generation.c, this sidesteps the problemof non-external MemoryChunks being unable to represent chunk sizes >= 1GB.This is less of a problem for aset.c as we store the free list index inthe MemoryChunk's spare 30-bit field (the value of which will never beclose to using all 30-bits). We can easily reverse engineer the chunk sizefrom this when needed. Storing this saves AllocSetFree() from having tomake a call to AllocSetFreeIndex() to determine which free list to put thenewly freed chunk on.For the slab allocator, this commit adds a new restriction that slabchunks cannot be >= 1GB in size. If there happened to be any users ofslab.c which used chunk sizes this large, they really should be usingAllocSet instead.Here we also add a restriction that normal non-dedicated blocks cannot be1GB or larger. It's now not possible to pass a 'maxBlockSize' >= 1GBduring the creation of an AllocSet or Generation context. Allocations canstill be larger than 1GB, it's just these will always be on dedicatedblocks (which do not have the 1GB restriction).Author: Andres Freund, David RowleyDiscussion:https://postgr.es/m/CAApHDvpjauCRXcgcaL6+e3eqecEHoeRm9D-kcbuvBitgPnW=vw@mail.gmail.com1 parentd2169c9 commitc6e0fe1
File tree
10 files changed
+1056
-618
lines changed- src
- backend/utils/mmgr
- include
- nodes
- utils
- tools/pgindent
10 files changed
+1056
-618
lines changedLines changed: 40 additions & 20 deletions
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
384 | 384 |
| |
385 | 385 |
| |
386 | 386 |
| |
387 |
| - | |
388 |
| - | |
389 |
| - | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
390 | 390 |
| |
391 |
| - | |
| 391 | + | |
392 | 392 |
| |
393 | 393 |
| |
394 | 394 |
| |
395 | 395 |
| |
396 | 396 |
| |
397 |
| - | |
398 |
| - | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
399 | 402 |
| |
400 | 403 |
| |
401 | 404 |
| |
402 |
| - | |
403 |
| - | |
404 |
| - | |
405 |
| - | |
406 |
| - | |
407 |
| - | |
408 |
| - | |
409 |
| - | |
410 |
| - | |
411 |
| - | |
412 |
| - | |
413 |
| - | |
414 |
| - | |
415 |
| - | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
416 | 436 |
| |
417 | 437 |
| |
418 | 438 |
| |
|
0 commit comments
Comments
(0)