201 static const size_type BIT_NOTEXACTSIZE = 2;
209 getChunkSize ()
const
211 return m_size & BIT_MASK;
215 getPrevChunkSize ()
const
217 return m_prevFootSize & BIT_MASK;
247 return m_size & BIT_USED;
251 isPrevChunkUsed ()
const
253 return m_prevFootSize & BIT_USED;
260 if (m_size & BIT_NOTEXACTSIZE)
284 m_size |= BIT_NOTEXACTSIZE;
295 return (MemChunk*)((
char*)
this - getPrevChunkSize ());
301 return (MemChunk*)((
char*)
this +
chunkSize);
304 inline const MemChunk*
305 getNextChunk ()
const
307 return (
const MemChunk*)((
char*)
this + getChunkSize ());
313 const MemChunk*
nextChunk = getNextChunk (getChunkSize ());
314 return getChunkSize () ==
nextChunk->getPrevChunkSize () &&
315 isUsed () ==
nextChunk->isPrevChunkUsed ();
321 printf (
"-- chunk[ %p ]: size: %zu, used = %s, exact size: %zu\n",
322 static_cast<const void*
> (
this),
324 (isUsed () ?
"true " :
"false"),
332 struct SmallMemChunk :
public MemChunk
341 friend class MemPool;
371 m_pad = MemChunk::BIT_USED;
376 size_type chunkSize = getMaxChunkSize ();
377 MemChunk* chunk = getFirstChunk ();
378 chunk->setFreeChunkSize (chunkSize);
379 chunk->getNextChunk (chunkSize)->setFence ();
386 return (MemChunk*)(((
char*)
this) + offsetof (MemSegment, m_pad));
390 getFirstChunk ()
const
392 return (
const MemChunk*)(((
char*)
this) + offsetof (MemSegment, m_pad));
398 return (MemChunk*)(((
char*)getFirstChunk ()) + getMaxChunkSize ());
402 getPastLastChunk ()
const
404 return (MemChunk*)(((
char*)getFirstChunk ()) + getMaxChunkSize ());
420 setNext (MemSegment* seg)
426 getMaxChunkSize ()
const
428 return (m_size - SEGMENT_OVERHEAD) & MemChunk::BIT_MASK;
434 printf (
"== segment %p, size: %zu, header: %zu, footer: %zu\n",
static_cast<const void*
> (
this), m_size, offsetof(MemSegment, m_pad),
sizeof(MemChunk));
435 const MemChunk* chunk = getFirstChunk ();
436 const MemChunk* lastChunk = getPastLastChunk ();
439 if (chunk < lastChunk)
442 chunk = chunk->getNextChunk ();
446 printf (
"-- chunk[ %p ]: size: %zu\n",
447 static_cast<const void*
> (chunk),
448 chunk->getChunkSize ());
466 static const size_type ALIGN_MASK = ALIGNMENT - 1;
469 static_assert (ALIGNMENT >= 4,
"ALLOCATION_ALIGNMENT must be at least 4.");
470 static_assert (ALIGN_MASK == ~MemChunk::BIT_MASK,
471 "ALLOCATION_ALIGNMENT must match MemChunk::BIT_MASK.");
486 static const size_type SMALLBIN_SHIFT = 3;
490 static const size_type TREEBIN_SHIFT = 8;
494 static const size_type MIN_LARGE_SIZE = (1UL << TREEBIN_SHIFT);
498 static const size_type CHUNK_OVERHEAD =
sizeof(MemChunk);
502 static const size_type MIN_LARGE_REQUEST = MIN_LARGE_SIZE - CHUNK_OVERHEAD - ALIGN_MASK;
506 static const size_type MIN_CHUNK_SIZE = ((
sizeof(SmallMemChunk) + ALIGN_MASK) & ~ALIGN_MASK);
510 static const size_type MAX_REQUEST = (
static_cast<size_type>(-
static_cast<long>(MIN_CHUNK_SIZE)) << 2);
515 static const size_type MIN_REQUEST = MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
521 static const size_type SEGMENT_HEADER = offsetof (MemSegment, m_pad);
525 static const size_type SEGMENT_OVERHEAD = ((((SEGMENT_HEADER + ALIGN_MASK) & ~ALIGN_MASK) +
sizeof(MemChunk) + +ALIGN_MASK) & ~ALIGN_MASK);
544 MemSegment* m_segList;
558 BinIndexType m_smallMap;
559 BinIndexType m_treeMap;
569 CircularList<SmallMemChunk> m_smallLists[NSMALLBINS];
573 PtrTreeType m_largeTrees[NTREEBINS];
587 bool m_storingExactSize;
593 const std::uint8_t m_padding;
615 m_footprintLimit (0),
645 MemSegment*
seg = m_segList;
651 m_logger.logFreeSegment (
ptr, size);
652 m_arena.freeSegment (
ptr, size);
678 return m_footprintLimit;
697 m_trimEmptySegmentsInterval =
interval;
709 return m_trimEmptySegmentsInterval;
742 return m_immediateReleaseThreshold;
758 if (
chunk ==
nullptr)
808 if (
chunk ==
nullptr)
814 std::uintptr_t
mem =
reinterpret_cast<std::uintptr_t
> (chunk2Mem (
chunk));
970 if (
num != 0 && size > (MAX_REQUEST /
num))
972 m_logger.logAllocation (
nullptr, MAX_REQUEST,
MEM_ALLOC_BIG);
998 if (!
chunk->isUsed())
1002 COOKMEM_ASSERT (
chunk->isValidSize ());
1006 COOKMEM_ASSERT (
chunkSize > CHUNK_OVERHEAD);
1009#if COOKMEM_DEBUG > 0
1016 for (std::uint8_t
i = 0;
i < m_padding; ++
i)
1024 m_logger.logDeallocation (
ptr,
chunk->getUserSize ());
1025 chunk->clearUsed ();
1067 if (m_immediateReleaseThreshold != 0 &&
1068 chunkSize >= m_immediateReleaseThreshold &&
1075 if (m_numFrees >= m_trimEmptySegmentsInterval)
1077 trimEmptySegments ();
1082 m_logger.logDeallocation (
ptr, size);
1102 MemSegment*
seg = m_segList;
1105 if (
reinterpret_cast<char*
>(
ptr) >=
reinterpret_cast<char*
>(
seg) &&
1106 reinterpret_cast<char*
>(
ptr) <= (
reinterpret_cast<char*
>(
seg) +
seg->getSize ()))
1111 return chunk->isUsed ();
1126 COOKMEM_ASSERT ((m_dv ==
nullptr && m_dvSize == 0) ||
1129 m_dv->getChunkSize () == m_dvSize));
1135 COOKMEM_ASSERT (isTreeMapMarked (
binIndex) == !treeAt (
binIndex).isEmpty ());
1138 MemSegment*
seg = m_segList;
1145 MemChunk*
chunk =
seg->getPastLastChunk ();
1162 if (!
chunk->isPrevChunkUsed ())
1164 COOKMEM_ASSERT (isValidChunk (
prevChunk));
1166 COOKMEM_ASSERT (
chunk->isUsed ());
1173 COOKMEM_ASSERT (
remainSize == SEGMENT_OVERHEAD &&
1205 if (
chunk->isUsed ())
1207 return chunk->getUserSize ();
1218 MemSegment*
seg = m_segList;
1224 m_logger.logFreeSegment (
ptr, size);
1225 m_arena.freeSegment (
ptr, size);
1227 m_segList =
nullptr;
1233 memset ((
void*)m_largeTrees, 0,
sizeof(m_largeTrees));
1234 memset ((
void*)m_smallLists, 0,
sizeof(m_smallLists));
1256 return m_maxFootprint;
1267 return m_storingExactSize;
1283 m_storingExactSize =
b;
1297 return m_padding != 0;
1317 return (std::uint8_t)m_paddingByte;
1339 printf (
"**** context: %p ****\n",
static_cast<const void*
> (
this));
1341 MemSegment*
seg = m_segList;
1356 trimEmptySegments ()
1358 m_logger.logTrimEmptySegments ();
1359 MemSegment*
seg = m_segList;
1360 MemSegment*
prevSeg =
nullptr;
1385 if (prevSeg !=
nullptr)
1387 prevSeg->setNext (nextSeg);
1407 isWholeSegment (MemChunk* chunk)
1411 return chunk->getPrevChunkSize () == 0 &&
1412 chunk->getNextChunk (chunk->getChunkSize ())->getChunkSize () == 0;
1422 releaseSegment (MemChunk* chunk)
1424 MemSegment* seg =
reinterpret_cast<MemSegment*
> (
reinterpret_cast<char*
> (chunk) - SEGMENT_HEADER);
1425 COOKMEM_ASSERT (seg->getFirstChunk () == chunk &&
1426 chunk->getChunkSize () == seg->getMaxChunkSize ());
1428 MemSegment* prevSeg =
nullptr;
1429 for (MemSegment* s = m_segList; s != seg; s = s->getNext ())
1431 COOKMEM_ASSERT (s !=
nullptr);
1434 if (prevSeg ==
nullptr)
1436 m_segList = seg->getNext ();
1440 prevSeg->setNext (seg->getNext ());
1443 removeChunk (chunk);
1446 m_footprint -= segSize;
1447 m_logger.logFreeSegment (seg, segSize);
1448 m_arena.freeSegment (seg, segSize);
1451 static inline BinIndexType
1452 idx2bit (BinIndexType binIndex)
1454 return ((BinIndexType) (1) << (binIndex));
1464 chunk2Mem (MemChunk* chunk)
1466 return ((T*)((
char*)(chunk) +
sizeof(MemChunk)));
1475 static inline MemChunk*
1478 return ((MemChunk*)((
char*)(mem) -
sizeof(MemChunk)));
1492 return (((requestSize) + CHUNK_OVERHEAD + ALIGN_MASK) & ~ALIGN_MASK);
1496 getSmallBinSize (BinIndexType binIndex)
1498 return ((binIndex) << SMALLBIN_SHIFT);
1501 static inline BinIndexType
1504 return (BinIndexType) ((size) >> SMALLBIN_SHIFT);
1510 return ((size) >> SMALLBIN_SHIFT) < NSMALLBINS;
1514 treeAt (BinIndexType i)
1516 return m_largeTrees[i];
1527 getTreeBinMinSize (BinIndexType binIndex)
1529 return (
static_cast<size_type> (1) << ((binIndex >> 1) + TREEBIN_SHIFT)) |
1530 (
static_cast<size_type> (binIndex & 1) << ((binIndex >> 1) + TREEBIN_SHIFT - 1));
1547 MemChunk* chunk =
nullptr;
1550 BinIndexType binIndex;
1551 cookmem_getLargeBinIndex (size, binIndex);
1555 for (; binIndex < NTREEBINS && getTreeBinMinSize (binIndex) < limit; ++binIndex)
1557 PtrTreeType& tree = treeAt (binIndex);
1558 if (!tree.isEmpty ())
1560 chunk =
reinterpret_cast<MemChunk*
>(tree.remove(actualSize, limit));
1561 if (chunk !=
nullptr)
1563 if (tree.isEmpty ())
1565 clearTreeMap (binIndex);
1572 if (chunk !=
nullptr)
1574 return splitChunk (chunk, size);
1594 if (allocSize < MIN_LARGE_REQUEST)
1596 BinIndexType binIndex;
1597 BinIndexType smallBits;
1598 chunkSize = (allocSize < MIN_REQUEST) ? MIN_CHUNK_SIZE : calcChunkSize (allocSize);
1599 binIndex = getSmallBinIndex (chunkSize);
1600 smallBits = m_smallMap >> binIndex;
1607 if ((smallBits & 0x3U) != 0)
1610 binIndex += ~smallBits & 1;
1612 chunk = removeSmallChunkList (binIndex);
1613 COOKMEM_ASSERT(chunk !=
nullptr && chunk->getChunkSize () == getSmallBinSize (binIndex));
1620 if (chunkSize > m_dvSize &&
1626 BinIndexType leftbits = (smallBits << binIndex) & left_bits(idx2bit(binIndex));
1627 BinIndexType leastbit = least_bit(leftbits);
1628 cookmem_bit2treeIndex(leastbit, i);
1630 chunk = removeSmallChunkList (i);
1631 COOKMEM_ASSERT(chunk !=
nullptr && chunk->getChunkSize () == getSmallBinSize (i));
1634 return splitChunk (chunk, chunkSize);
1638 else if (allocSize >= MAX_REQUEST)
1645 chunkSize = calcChunkSize (allocSize);
1650 if (allocSize < MIN_LARGE_REQUEST &&
1651 m_dvSize >= chunkSize)
1654 return takeDesignatedVictim (chunkSize);
1666 chunk = treeMalloc (chunkSize, (m_dvSize >= chunkSize) ? m_dvSize : ~static_cast<
size_type> (0));
1667 if (chunk !=
nullptr)
1677 if (chunk ==
nullptr &&
1678 m_dvSize >= chunkSize)
1680 chunk = takeDesignatedVictim (chunkSize);
1687 if (chunk ==
nullptr)
1689 chunk = arenaAlloc (chunkSize);
1708 splitChunk (MemChunk* chunk,
size_type size)
1711 size_type remainSize = chunk->getChunkSize () - size;
1713 if (remainSize >= MIN_CHUNK_SIZE)
1715 MemChunk* remainChunk = (MemChunk*)((
char*)chunk + size);
1717 chunk->setFreeChunkSize (size);
1719 remainChunk->setFreeChunkSize (remainSize);
1721 addChunk (remainChunk);
1739 MemChunk* chunk = m_dv;
1742 if (remainSize >= MIN_CHUNK_SIZE)
1744 MemChunk* remainChunk = (MemChunk*)((
char*)chunk + size);
1745 chunk->setFreeChunkSize (size);
1746 remainChunk->setFreeChunkSize (remainSize);
1748 if (!isSmallChunk (remainSize))
1753 m_dvSize = remainSize;
1759 addSmallChunk (remainChunk);
1781 estSize = chunkSize + SEGMENT_OVERHEAD;
1782 if (estSize <= chunkSize)
1793 if (m_footprintLimit != 0)
1796 if (fp <= m_footprint || fp > m_footprintLimit)
1806 MemSegment* seg = (MemSegment*)m_arena.getSegment (segSize);
1807 m_logger.logGetSegment (seg, segSize);
1814 if ((m_footprint += segSize) > m_maxFootprint)
1816 m_maxFootprint = m_footprint;
1819 MemChunk* chunk = seg->init (segSize);
1821 if (m_segList ==
nullptr)
1824 seg->setNext (
nullptr);
1828 seg->setNext (m_segList);
1832 return splitChunk (chunk, chunkSize);
1837 inline CircularList<SmallMemChunk>&
1838 getSmallChunkList (BinIndexType binIndex)
1840 return m_smallLists[binIndex];
1844 addSmallChunk (MemChunk* chunk)
1846 BinIndexType I = getSmallBinIndex(chunk->getChunkSize());
1848 CircularList<SmallMemChunk>& freeList = getSmallChunkList(I);
1849 freeList.add ((SmallMemChunk*)chunk);
1850 if (!isSmallMapMarked(I))
1855 removeSmallChunkList (BinIndexType binIndex)
1857 CircularList<SmallMemChunk>& freeList = getSmallChunkList (binIndex);
1858 SmallMemChunk* chunk = freeList.remove();
1859 if (freeList.isEmpty ())
1861 clearSmallMap (binIndex);
1867 removeSmallChunk (MemChunk* chunk)
1869 BinIndexType binIndex = getSmallBinIndex (chunk->getChunkSize ());
1871 CircularList<SmallMemChunk>& freeList = getSmallChunkList (binIndex);
1872 if (freeList.remove ((SmallMemChunk*)chunk))
1874 clearSmallMap (binIndex);
1879 markSmallMap (BinIndexType binIndex)
1881 m_smallMap |= idx2bit(binIndex);
1885 clearSmallMap (BinIndexType binIndex)
1887 m_smallMap &= ~idx2bit(binIndex);
1891 isSmallMapMarked (BinIndexType binIndex)
1893 return m_smallMap & idx2bit (binIndex);
1897 markTreeMap (BinIndexType binIndex)
1899 m_treeMap |= idx2bit (binIndex);
1903 clearTreeMap (BinIndexType binIndex)
1905 m_treeMap &= ~idx2bit (binIndex);
1909 isTreeMapMarked (BinIndexType binIndex)
1911 return m_treeMap & idx2bit (binIndex);
1915 addLargeChunk (MemChunk* chunk)
1917 BinIndexType treeBinIndex;
1918 cookmem_getLargeBinIndex(chunk->getChunkSize(), treeBinIndex);
1919 PtrTreeType& tree = treeAt (treeBinIndex);
1920 if (!isTreeMapMarked (treeBinIndex))
1922 markTreeMap (treeBinIndex);
1924 tree.add(chunk, chunk->getChunkSize());
1928 removeLargeChunk (MemChunk* chunk)
1930 BinIndexType treeBinIndex;
1931 cookmem_getLargeBinIndex (chunk->getChunkSize(), treeBinIndex);
1932 PtrTreeType& tree = treeAt (treeBinIndex);
1934 tree.remove (chunk);
1935 if (tree.isEmpty ())
1937 clearTreeMap (treeBinIndex);
1942 isValidChunk (MemChunk* chunk)
1949 if (isSmallChunk (chunk->getChunkSize ()))
1951 BinIndexType I = getSmallBinIndex (chunk->getChunkSize ());
1953 CircularList<SmallMemChunk>& freeList = getSmallChunkList (I);
1954 return freeList.contains ((SmallMemChunk*)chunk);
1958 BinIndexType treeBinIndex;
1959 cookmem_getLargeBinIndex (chunk->getChunkSize (), treeBinIndex);
1960 PtrTreeType& tree = treeAt (treeBinIndex);
1961 return tree.contains (chunk);
1981 growFreeChunkInPlace (MemChunk* chunk,
size_type extraSize)
1983 size_type oldSize = chunk->getChunkSize ();
1984 size_type newSize = oldSize + extraSize;
1988 chunk->setFreeChunkSize (newSize);
1993 if (isSmallChunk (oldSize))
2002 if ((oldSize ^ newSize) > (oldSize >> 2))
2007 BinIndexType treeBinIndex;
2008 cookmem_getLargeBinIndex (oldSize, treeBinIndex);
2009 if (!treeAt (treeBinIndex).canGrowInPlace (chunk, newSize))
2016 chunk->setFreeChunkSize (newSize);
2021 addChunk (MemChunk* chunk)
2023 if (isSmallChunk(chunk->getChunkSize ()))
2025 addSmallChunk (chunk);
2027 else if (m_dv ==
nullptr)
2030 m_dvSize = chunk->getChunkSize ();
2034 addLargeChunk (chunk);
2039 removeChunk (MemChunk* chunk)
2046 else if (isSmallChunk (chunk->getChunkSize ()))
2048 removeSmallChunk (chunk);
2052 removeLargeChunk (chunk);
2066 if (userSize > (MAX_REQUEST - m_padding - 1))
2071 return userSize + m_padding + 1;
2075 setUsed (MemChunk* chunk,
size_type userSize)
2077 chunk->setUsedSize (m_storingExactSize, userSize);
2083 char* paddingPtr = ((
char*)chunk) + userSize + CHUNK_OVERHEAD;
2084 for (std::uint8_t i = 0; i < m_padding; ++i)
2086 paddingPtr[i] = m_paddingByte;
2094 T* userPtr = chunk2Mem (chunk);
2095 m_logger.logAllocation (userPtr, userSize, allocType);