📄 system.cpp
字号:
}
} else {
// In one of our heaps.
// See how big the block really was
size_t realSize = ((uint32*)ptr)[-1];
if (bytes <= realSize) {
// The old block was big enough.
return ptr;
}
// Need to reallocate
void* newPtr = malloc(bytes);
System::memcpy(newPtr, ptr, realSize);
free(ptr);
return newPtr;
}
}
void* malloc(size_t bytes) {
lock();
++totalMallocs;
if (bytes <= tinyBufferSize) {
void* ptr = tinyMalloc(bytes);
if (ptr) {
++mallocsFromTinyPool;
unlock();
return ptr;
}
}
// Failure to allocate a tiny buffer is allowed to flow
// through to a small buffer
if (bytes <= smallBufferSize) {
void* ptr = malloc(smallPool, smallPoolSize, bytes);
if (ptr) {
++mallocsFromSmallPool;
unlock();
return ptr;
}
} else if (bytes <= medBufferSize) {
// Note that a small allocation failure does *not* fall
// through into a medium allocation because that would
// waste the medium buffer's resources.
void* ptr = malloc(medPool, medPoolSize, bytes);
if (ptr) {
++mallocsFromMedPool;
unlock();
return ptr;
}
}
bytesAllocated += 4 + (int) bytes;
unlock();
// Heap allocate
// Allocate 4 extra bytes for our size header (unfortunate,
// since malloc already added its own header).
void* ptr = ::malloc(bytes + 4);
if (ptr == NULL) {
// Flush memory pools to try and recover space
flushPool(smallPool, smallPoolSize);
flushPool(medPool, medPoolSize);
ptr = ::malloc(bytes + 4);
}
if (ptr == NULL) {
if ((System::outOfMemoryCallback != NULL) &&
(System::outOfMemoryCallback(bytes + 4, true) == true)) {
// Re-attempt the malloc
ptr = ::malloc(bytes + 4);
}
}
if (ptr == NULL) {
if (System::outOfMemoryCallback != NULL) {
// Notify the application
System::outOfMemoryCallback(bytes + 4, false);
}
return NULL;
}
*(uint32*)ptr = (uint32)bytes;
return (uint8*)ptr + 4;
}
void free(void* ptr) {
if (ptr == NULL) {
// Free does nothing on null pointers
return;
}
debugAssert(isValidPointer(ptr));
if (inTinyHeap(ptr)) {
lock();
tinyFree(ptr);
unlock();
return;
}
uint32 bytes = ((uint32*)ptr)[-1];
lock();
if (bytes <= smallBufferSize) {
if (smallPoolSize < maxSmallBuffers) {
smallPool[smallPoolSize] = MemBlock(ptr, bytes);
++smallPoolSize;
unlock();
return;
}
} else if (bytes <= medBufferSize) {
if (medPoolSize < maxMedBuffers) {
medPool[medPoolSize] = MemBlock(ptr, bytes);
++medPoolSize;
unlock();
return;
}
}
bytesAllocated -= bytes + 4;
unlock();
// Free; the buffer pools are full or this is too big to store.
::free((uint8*)ptr - 4);
}
std::string performance() const {
if (totalMallocs > 0) {
int pooled = mallocsFromTinyPool +
mallocsFromSmallPool +
mallocsFromMedPool;
int total = totalMallocs;
return format("malloc performance: %5.1f%% <= %db, %5.1f%% <= %db, "
"%5.1f%% <= %db, %5.1f%% > %db",
100.0 * mallocsFromTinyPool / total,
BufferPool::tinyBufferSize,
100.0 * mallocsFromSmallPool / total,
BufferPool::smallBufferSize,
100.0 * mallocsFromMedPool / total,
BufferPool::medBufferSize,
100.0 * (1.0 - (double)pooled / total),
BufferPool::medBufferSize);
} else {
return "No System::malloc calls made yet.";
}
}
std::string status() const {
return format("preallocated shared buffers: %5d/%d x %db",
maxTinyBuffers - tinyPoolSize, maxTinyBuffers, tinyBufferSize);
}
};
// Dynamically allocated because we need to ensure that
// the buffer pool is still around when the last global variable
// is deallocated.
static BufferPool* bufferpool = NULL;
std::string System::mallocPerformance() {
#ifndef NO_BUFFERPOOL
return bufferpool->performance();
#else
return "NO_BUFFERPOOL";
#endif
}
std::string System::mallocStatus() {
#ifndef NO_BUFFERPOOL
return bufferpool->status();
#else
return "NO_BUFFERPOOL";
#endif
}
void System::resetMallocPerformanceCounters() {
#ifndef NO_BUFFERPOOL
bufferpool->totalMallocs = 0;
bufferpool->mallocsFromMedPool = 0;
bufferpool->mallocsFromSmallPool = 0;
bufferpool->mallocsFromTinyPool = 0;
#endif
}
#ifndef NO_BUFFERPOOL
inline void initMem() {
// Putting the test here ensures that the system is always
// initialized, even when globals are being allocated.
static bool initialized = false;
if (! initialized) {
bufferpool = new BufferPool();
initialized = true;
}
}
#endif
void* System::malloc(size_t bytes) {
#ifndef NO_BUFFERPOOL
initMem();
return bufferpool->malloc(bytes);
#else
return ::malloc(bytes);
#endif
}
void* System::calloc(size_t n, size_t x) {
#ifndef NO_BUFFERPOOL
void* b = System::malloc(n * x);
System::memset(b, 0, n * x);
return b;
#else
return ::calloc(n, x);
#endif
}
void* System::realloc(void* block, size_t bytes) {
#ifndef NO_BUFFERPOOL
initMem();
return bufferpool->realloc(block, bytes);
#else
return ::realloc(block, bytes);
#endif
}
void System::free(void* p) {
#ifndef NO_BUFFERPOOL
bufferpool->free(p);
#else
return ::free(p);
#endif
}
void* System::alignedMalloc(size_t bytes, size_t alignment) {
alwaysAssertM(isPow2(alignment), "alignment must be a power of 2");
// We must align to at least a word boundary.
alignment = iMax((int)alignment, sizeof(void *));
// Pad the allocation size with the alignment size and the
// size of the redirect pointer.
size_t totalBytes = bytes + alignment + sizeof(intptr_t);
void* truePtr = System::malloc(totalBytes);
if (!truePtr) {
// malloc returned NULL
return NULL;
}
debugAssert(isValidHeapPointer(truePtr));
#ifdef G3D_WIN32
// The blocks we return will not be valid Win32 debug heap
// pointers because they are offset
// debugAssert(_CrtIsValidPointer(truePtr, totalBytes, TRUE) );
#endif
// The return pointer will be the next aligned location (we must at least
// leave space for the redirect pointer, however).
char* alignedPtr = ((char*)truePtr)+ sizeof(intptr_t);
#if 0
// 2^n - 1 has the form 1111... in binary.
uint32 bitMask = (alignment - 1);
// Advance forward until we reach an aligned location.
while ((((intptr_t)alignedPtr) & bitMask) != 0) {
alignedPtr += sizeof(void*);
}
#else
alignedPtr += alignment - (((intptr_t)alignedPtr) & (alignment - 1));
// assert((alignedPtr - truePtr) + bytes <= totalBytes);
#endif
debugAssert((alignedPtr - truePtr) + bytes <= totalBytes);
// Immediately before the aligned location, write the true array location
// so that we can free it correctly.
intptr_t* redirectPtr = (intptr_t*)(alignedPtr - sizeof(intptr_t));
redirectPtr[0] = (intptr_t)truePtr;
debugAssert(isValidHeapPointer(truePtr));
#ifdef G3D_WIN32
debugAssert( _CrtIsValidPointer(alignedPtr, bytes, TRUE) );
#endif
return (void*)alignedPtr;
}
void System::alignedFree(void* _ptr) {
if (_ptr == NULL) {
return;
}
char* alignedPtr = (char*)_ptr;
// Back up one word from the pointer the user passed in.
// We now have a pointer to a pointer to the true start
// of the memory block.
intptr_t* redirectPtr = (intptr_t*)(alignedPtr - sizeof(intptr_t));
// Dereference that pointer so that ptr = true start
void* truePtr = (void*)(redirectPtr[0]);
debugAssert(isValidHeapPointer(truePtr));
System::free(truePtr);
}
} // namespace
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -