/* -*- C++ -*- */ /* Heap Layers: An Extensible Memory Allocation Infrastructure Copyright (C) 2000-2020 by Emery Berger http://www.emeryberger.com emery@cs.umass.edu Heap Layers is distributed under the terms of the Apache 2.0 license. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 */ #ifndef HL_DLHEAP_H #define HL_DLHEAP_H /** * @file dlheap.h * @brief Contains all the classes required to approximate DLmalloc 2.7.0. * @author Emery Berger */ #include #include "heaps/buildingblock/adaptheap.h" #include "utility/dllist.h" #include "utility/sllist.h" #include "heaps/objectrep/coalesceableheap.h" #include "heaps/buildingblock/coalesceheap.h" #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif /** * @class CoalesceableMmapHeap * @brief Adds headers to mmapped objects to allow coalescing. * @author Emery Berger */ namespace HL { template class CoalesceableMmapHeap : public RequireCoalesceable { public: typedef RequireCoalesceable super; typedef typename RequireCoalesceable::Header Header; inline void * malloc (const size_t sz) { void * buf = super::malloc (sz + sizeof(Header)); void * ptr = Header::makeObject (buf, 0, sz); super::markMmapped (ptr); super::markInUse (ptr); return ptr; } inline void free (void * ptr) { super::free (Header::getHeader (ptr)); } inline int remove (void * ptr) { return super::remove (Header::getHeader (ptr)); } }; /** * @class SelectMmapHeap * @brief Use Mmap (here the superheap) for objects above a certain size. * @author Emery Berger * * @param ThresholdBytes The maximum number of bytes managed by SmallHeap. * @param SmallHeap The heap for "small" objects. * @param super The heap for "large" objects. */ template class SelectMmapHeap : public super { public: inline void * malloc (const size_t sz) { void * ptr = NULL; if (sz <= ThresholdBytes) { ptr = sm.malloc (sz); } // Fall-through: go ahead and try mmap if the small heap is out of memory. if (ptr == NULL) { ptr = super::malloc (sz); super::markMmapped (ptr); } return ptr; } inline void free (void * ptr) { if (super::isMmapped(ptr)) { super::free (ptr); } else { sm.free (ptr); } } inline int remove (void * ptr) { if (super::isMmapped(ptr)) { return super::remove (ptr); } else { return sm.remove (ptr); } } inline void clear (void) { sm.clear(); super::clear(); } private: SmallHeap sm; }; // LeaHeap 2.7.0-like threshold scheme // for managing a small superheap. // NOTE: THIS HAS BEEN CHANGED NOW! template class Threshold : public super { public: enum { MIN_LARGE_SIZE = 64 }; #if 1 Threshold (void) : freeAllNextMalloc (FALSE), inUse (0), maxInUse (0), threshold (0) {} inline void * malloc (const size_t sz) { void * ptr = super::malloc (sz); if (ptr) { const size_t actualSize = super::getSize(ptr); inUse += actualSize; if (inUse > maxInUse) { maxInUse = inUse; threshold = 16384 + maxInUse / 2; } #if 0 if (freed < 0) { freed = 0; } #endif } return ptr; } #if 0 void * internalMalloc (const size_t sz) { if (freeAllNextMalloc || (freed > 0)) { freed = 0; super::freeAll(); freeAllNextMalloc = FALSE; } void * ptr = super::malloc (sz); if (ptr != NULL) { if (sz < MIN_LARGE_SIZE) { freed -= getSize(ptr); if (freed < 0) { freed = 0; } } } return ptr; } #endif inline void free (void * ptr) { const size_t sz = super::getSize(ptr); inUse -= sz; super::free (ptr); if (super::getMemoryHeld() > threshold) { super::freeAll(); } } private: /// The number of bytes in use. size_t inUse; /// The high-water mark of bytes in use. size_t maxInUse; size_t threshold; // How many bytes have been freed (whose requests were below MIN_LARGE_SIZE). // int freed; /// Should we free all in the superheap on the next malloc? bool freeAllNextMalloc; #else inline Threshold (void) {} inline void * malloc (const size_t sz) { if ((getMemoryHeld() > ThresholdBytes) || ((sz >= MIN_LARGE_SIZE) && (getMemoryHeld() >= sz))) { super::freeAll(); } return super::malloc (sz); } #endif }; /** * @namespace DLBigHeapNS * @brief All of the bins & size functions for the "big heap". */ namespace DLBigHeapNS { const size_t bins[] = {8U, 16U, 24U, 32U, 40U, 48U, 56U, 64U, 72U, 80U, 88U, 96U, 104U, 112U, 120U, 128U, 136U, 144U, 152U, 160U, 168U, 176U, 184U, 192U, 200U, 208U, 216U, 224U, 232U, 240U, 248U, 256U, 264U, 272U, 280U, 288U, 296U, 304U, 312U, 320U, 328U, 336U, 344U, 352U, 360U, 368U, 376U, 384U, 392U, 400U, 408U, 416U, 424U, 432U, 440U, 448U, 456U, 464U, 472U, 480U, 488U, 496U, 504U, 512U, 576U, 640U, 704U, 768U, 832U, 896U, 960U, 1024U, 1088U, 1152U, 1216U, 1280U, 1344U, 1408U, 1472U, 1536U, 1600U, 1664U, 1728U, 1792U, 1856U, 1920U, 1984U, 2048U, 2112U, 2560U, 3072U, 3584U, 4096U, 4608U, 5120U, 5632U, 6144U, 6656U, 7168U, 7680U, 8192U, 8704U, 9216U, 9728U, 10240U, 10752U, 12288U, 16384U, 20480U, 24576U, 28672U, 32768U, 36864U, 40960U, 65536U, 98304U, 131072U, 163840U, 262144U, 524288U, 1048576U, 2097152U, 4194304U, 8388608U, 16777216U, 33554432U, 67108864U, 134217728U, 268435456U, 536870912U, 1073741824U, 2147483648U }; enum { NUMBINS = sizeof(bins) / sizeof(size_t) }; enum { BIG_OBJECT = 2147483648U }; /** * @brief Compute the log base two. * @param sz The value we want the log of. */ inline int log2 (const size_t sz) { int c = 0; size_t sz1 = sz; while (sz1 > 1) { sz1 >>= 1; c++; } return c; } inline int getSizeClass (const size_t sz); inline size_t getClassSize (const int i) { assert (i >= 0); assert (i < NUMBINS); #if 0 if (i < 64) { return ((size_t) ((i+1) << 3)); } else { return (i < 89) ? ((size_t) ((i - 55) << 6)) : (i < 106) ? ((size_t) ((i - 84) << 9)) : (i < 114) ? ((size_t) ((i - 103) << 12)) : (i < 118) ? ((size_t) ((i - 112) << 15)) : (i < 120) ? ((size_t) ((i - 117) * 262144)) : (i < 122) ? ((size_t) ((i - 119) * 1048576)) : (i < 124) ? ((size_t) ((i - 121) * 4 * 1048576)) : (i < 126) ? ((size_t) ((i - 123) * 16 * 1048576)) : (i < 128) ? ((size_t) ((i - 125) * 64 * 1048576)) : (i < 130) ? ((size_t) ((i - 127) * 256 * 1048576)) : ((size_t) ((i - 129) * 1024 * 1048576)); } #else #if 0 if (i < 64) { return (size_t) ((i+1) << 3); } #endif return bins[i]; #endif } inline int getSizeClass (const size_t sz) { size_t sz1 = sz - 1; if (sz1 <= 513) { return (int) (sz1 >> 3); } else { return (int) ((((sz1 >> 6) <= 32)? 56 + (sz1 >> 6): ((sz1 >> 9) <= 20)? 91 + (sz1 >> 9): ((sz1 >> 12) <= 10)? 110 - 6 + (sz1 >> 12): ((sz1 >> 15) <= 4)? 119 - 6 + (sz1 >> 15): ((sz1 >> 18) <= 2)? 124 - 6 + (sz1 >> 18): 126 - 6 + (size_t) log2(sz1>>19))); } } } /** * @namespace DLSmallHeapNS * @brief The size functions for the "small" heap (fastbins). */ namespace DLSmallHeapNS { enum { NUMBINS = 8 }; inline int getSizeClass (const size_t sz) { return (int) ((sz-1) >> 3); } inline size_t getClassSize (const int i) { assert (i >= 0); assert (i < NUMBINS); return (size_t) (((long) i+1) << 3); } } #if 0 #include "kingsleyheap.h" /** * @class DLBigHeapType * @brief The "big heap" -- a coalescing segregated-fits allocator. * @author Emery Berger */ template class DLBigHeapType : public CoalesceHeap >, super> > > {}; #else template class DLBigHeapType : public CoalesceHeap >, super> > > {}; #endif /** * @class DLSmallHeapType * @brief The "small heap" -- non-coalescing "fastbins" (quicklists). * @author Emery Berger */ template class DLSmallHeapType : public RequireCoalesceable< StrictSegHeap >, super> > {}; /** * @class LeaHeap * @brief This heap approximates the algorithms used by DLmalloc 2.7.0. * * The whole thing. Big objects are allocated via mmap. * Other objects are first allocated from the special thresholded quicklists, * or if they're too big, they're allocated from the coalescing big heap. * * @param Sbrk An sbrk-like heap, for small object allocation. * @param Mmap An mmap-like heap, for large object allocation. */ template class LeaHeap : public SelectMmapHeap<128 * 1024, Threshold<4096, DLSmallHeapType > > >, CoalesceableMmapHeap > {}; } #endif