22 #ifndef WIN32_LEAN_AND_MEAN 23 #define WIN32_LEAN_AND_MEAN 1 31 #include <sys/types.h> 35 #define MAP_ANON 0x1000 43 static_assert(MEMORY_HOOK_ALIGNMENT >=
sizeof(
size_t),
44 "MEMORY_HOOK_ALIGNMENT should at least be sizeof(size_t)");
45 static_assert(MEMORY_HOOK_ALIGNMENT >=
sizeof(
void *),
46 "MEMORY_HOOK_ALIGNMENT should at least be sizeof(void *)");
47 static_assert(MEMORY_HOOK_ALIGNMENT * 8 >= NATIVE_WORDSIZE,
48 "MEMORY_HOOK_ALIGNMENT * 8 should at least be NATIVE_WORDSIZE");
49 static_assert((MEMORY_HOOK_ALIGNMENT & (MEMORY_HOOK_ALIGNMENT - 1)) == 0,
50 "MEMORY_HOOK_ALIGNMENT should be a power of two");
52 #if defined(CPPPARSER) 54 #elif defined(USE_MEMORY_DLMALLOC) 60 #define DLMALLOC_EXPORT static 61 #define USE_DL_PREFIX 1 67 #define MALLOC_ALIGNMENT MEMORY_HOOK_ALIGNMENT 69 #include "dlmalloc_src.cxx" 71 #define call_malloc dlmalloc 72 #define call_realloc dlrealloc 73 #define call_free dlfree 74 #define MEMORY_HOOK_MALLOC_LOCK 1 76 #elif defined(USE_MEMORY_PTMALLOC2) 88 #define USE_DL_PREFIX 1 91 #define MALLOC_DEBUG 2 93 #include "ptmalloc2_smp_src.cxx" 95 #define call_malloc dlmalloc 96 #define call_realloc dlrealloc 97 #define call_free dlfree 98 #undef MEMORY_HOOK_MALLOC_LOCK 105 #define call_malloc malloc 106 #define call_realloc realloc 107 #define call_free free 108 #undef MEMORY_HOOK_MALLOC_LOCK 110 #endif // USE_MEMORY_* 117 inflate_size(
size_t size) {
118 #if defined(MEMORY_HOOK_DO_ALIGN) 121 return size +
sizeof(uintptr_t) * 2 + MEMORY_HOOK_ALIGNMENT - 1;
122 #elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) 126 #elif defined(DO_MEMORY_USAGE) 131 return size + MEMORY_HOOK_ALIGNMENT;
136 #endif // DO_MEMORY_USAGE 144 alloc_to_ptr(
void *alloc,
size_t size) {
145 #if defined(MEMORY_HOOK_DO_ALIGN) 147 uintptr_t *root = (uintptr_t *)((
char *)alloc +
sizeof(uintptr_t) * 2);
149 root = (uintptr_t *)(((uintptr_t)root + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1));
151 root[-1] = (uintptr_t)alloc;
153 #elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) 155 #elif defined(DO_MEMORY_USAGE) 156 size_t *root = (
size_t *)alloc;
158 return (
void *)((
char *)root + MEMORY_HOOK_ALIGNMENT);
161 #endif // DO_MEMORY_USAGE 170 ptr_to_alloc(
void *ptr,
size_t &size) {
171 #if defined(MEMORY_HOOK_DO_ALIGN) 172 uintptr_t *root = (uintptr_t *)ptr;
174 return (
void *)root[-1];
175 #elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) 176 #ifdef DO_MEMORY_USAGE 180 #elif defined(DO_MEMORY_USAGE) 181 size_t *root = (
size_t *)((
char *)ptr - MEMORY_HOOK_ALIGNMENT);
186 #endif // DO_MEMORY_USAGE 198 GetSystemInfo(&sysinfo);
200 _page_size = (size_t)sysinfo.dwPageSize;
205 _page_size = sysconf(_SC_PAGESIZE);
209 _total_heap_single_size = 0;
210 _total_heap_array_size = 0;
211 _requested_heap_size = 0;
212 _total_mmap_size = 0;
213 _max_heap_size = ~(size_t)0;
221 _total_heap_single_size(copy._total_heap_single_size),
222 _total_heap_array_size(copy._total_heap_array_size),
223 _requested_heap_size(copy._requested_heap_size),
224 _total_mmap_size(copy._total_mmap_size),
225 _max_heap_size(copy._max_heap_size),
226 _page_size(copy._page_size) {
229 _deleted_chains = copy._deleted_chains;
251 size_t inflated_size = inflate_size(size);
253 #ifdef MEMORY_HOOK_MALLOC_LOCK 255 void *alloc = call_malloc(inflated_size);
258 void *alloc = call_malloc(inflated_size);
261 while (alloc ==
nullptr) {
263 #ifdef MEMORY_HOOK_MALLOC_LOCK 265 alloc = call_malloc(inflated_size);
268 alloc = call_malloc(inflated_size);
272 #ifdef DO_MEMORY_USAGE 275 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) 278 inflated_size = size;
284 overflow_heap_size();
286 #endif // DO_MEMORY_USAGE 288 void *ptr = alloc_to_ptr(alloc, size);
290 assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
291 assert(ptr >= alloc && (
char *)ptr + size <= (
char *)alloc + inflated_size);
302 void *alloc = ptr_to_alloc(ptr, size);
304 #ifdef DO_MEMORY_USAGE 305 assert((
int)size <= _total_heap_single_size);
307 #endif // DO_MEMORY_USAGE 309 #ifdef MEMORY_HOOK_MALLOC_LOCK 328 size_t inflated_size = inflate_size(size);
330 #ifdef MEMORY_HOOK_MALLOC_LOCK 332 void *alloc = call_malloc(inflated_size);
335 void *alloc = call_malloc(inflated_size);
338 while (alloc ==
nullptr) {
340 #ifdef MEMORY_HOOK_MALLOC_LOCK 342 alloc = call_malloc(inflated_size);
345 alloc = call_malloc(inflated_size);
349 #ifdef DO_MEMORY_USAGE 352 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) 355 inflated_size = size;
361 overflow_heap_size();
363 #endif // DO_MEMORY_USAGE 365 void *ptr = alloc_to_ptr(alloc, size);
367 assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
368 assert(ptr >= alloc && (
char *)ptr + size <= (
char *)alloc + inflated_size);
379 void *alloc = ptr_to_alloc(ptr, orig_size);
381 size_t inflated_size = inflate_size(size);
383 void *alloc1 = alloc;
384 #ifdef MEMORY_HOOK_MALLOC_LOCK 386 alloc1 = call_realloc(alloc1, inflated_size);
389 alloc1 = call_realloc(alloc1, inflated_size);
392 while (alloc1 ==
nullptr) {
398 #ifdef MEMORY_HOOK_MALLOC_LOCK 400 alloc1 = call_realloc(alloc1, inflated_size);
403 alloc1 = call_realloc(alloc1, inflated_size);
407 #ifdef DO_MEMORY_USAGE 408 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) 411 inflated_size = size;
413 assert((AtomicAdjust::Integer)orig_size <= _total_heap_array_size);
414 AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size-(AtomicAdjust::Integer)orig_size);
415 #endif // DO_MEMORY_USAGE 418 #ifdef MEMORY_HOOK_DO_ALIGN 421 uintptr_t *root = (uintptr_t *)((
char *)alloc1 +
sizeof(uintptr_t) * 2);
422 root = (uintptr_t *)(((uintptr_t)root + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1));
423 void *ptr1 = (
void *)root;
425 size_t orig_delta = (
char *)ptr - (
char *)alloc;
426 size_t new_delta = (
char *)ptr1 - (
char *)alloc1;
427 if (orig_delta != new_delta) {
428 memmove((
char *)alloc1 + new_delta, (
char *)alloc1 + orig_delta, std::min(size, orig_size));
432 root[-1] = (uintptr_t)alloc1;
434 void *ptr1 = alloc_to_ptr(alloc1, size);
438 assert(ptr1 >= alloc1 && (
char *)ptr1 + size <= (
char *)alloc1 + inflated_size);
439 assert(((uintptr_t)ptr1 % MEMORY_HOOK_ALIGNMENT) == 0);
450 void *alloc = ptr_to_alloc(ptr, size);
452 #ifdef DO_MEMORY_USAGE 453 assert((
int)size <= _total_heap_array_size);
455 #endif // DO_MEMORY_USAGE 457 #ifdef MEMORY_HOOK_MALLOC_LOCK 477 bool trimmed =
false;
479 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) 484 if (dlmalloc_trim(pad)) {
492 if (_heapmin() == 0) {
513 assert((size % _page_size) == 0);
515 #ifdef DO_MEMORY_USAGE 516 _total_mmap_size += size;
522 void *ptr = VirtualAlloc(
nullptr, size, MEM_COMMIT | MEM_RESERVE,
523 allow_exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
524 if (ptr ==
nullptr) {
525 DWORD err = GetLastError();
526 cerr <<
"Couldn't allocate memory page of size " << size <<
": ";
530 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
531 nullptr, err, 0, (LPTSTR)&buffer, 0,
nullptr);
533 cerr << (
char *)buffer <<
"\n";
535 cerr <<
"Error code " << err <<
"\n";
546 int prot = PROT_READ | PROT_WRITE;
550 void *ptr = mmap(
nullptr, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
551 if (ptr == (
void *)-1) {
567 assert((size % _page_size) == 0);
569 #ifdef DO_MEMORY_USAGE 570 assert((
int)size <= _total_mmap_size);
571 _total_mmap_size -= size;
575 VirtualFree(ptr, 0, MEM_RELEASE);
602 DeletedChains::iterator dci = _deleted_chains.find(buffer_size);
603 if (dci != _deleted_chains.end()) {
604 chain = (*dci).second;
608 _deleted_chains.insert(DeletedChains::value_type(buffer_size, chain));
629 cerr <<
"Out of memory allocating " << attempted_size <<
" bytes\n";
642 overflow_heap_size() {
643 #ifdef DO_MEMORY_USAGE 644 _max_heap_size = ~(size_t)0;
645 #endif // DO_MEMORY_USAGE DeletedBufferChain * get_deleted_chain(size_t buffer_size)
Returns a pointer to a global DeletedBufferChain object suitable for allocating arrays of the indicat...
virtual void heap_free_array(void *ptr)
Releases a block of memory previously allocated via heap_alloc_array.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void * heap_alloc_single(size_t size)
Allocates a block of memory from the heap, similar to malloc().
virtual void mark_pointer(void *ptr, size_t orig_size, ReferenceCount *ref_ptr)
This special method exists only to provide a callback hook into MemoryUsage.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static Integer add(Integer &var, Integer delta)
Atomically computes var += delta.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void mmap_free(void *ptr, size_t size)
Frees a block of memory previously allocated via mmap_alloc().
virtual void heap_free_single(void *ptr)
Releases a block of memory previously allocated via heap_alloc_single.
static Integer get(const Integer &var)
Atomically retrieves the snapshot value of the indicated variable.
A base class for all things that want to be reference-counted.
virtual void * heap_alloc_array(size_t size)
Allocates a block of memory from the heap, similar to malloc().
This class provides a wrapper around the various possible malloc schemes Panda might employ.
virtual void * heap_realloc_array(void *ptr, size_t size)
Resizes a block of memory previously returned from heap_alloc_array.
virtual void alloc_fail(size_t attempted_size)
This callback method is called whenever a low-level call to call_malloc() has returned NULL,...
This template class can be used to provide faster allocation/deallocation for many Panda objects.
virtual void * mmap_alloc(size_t size, bool allow_exec)
Allocates a raw page or pages of memory directly from the OS.
bool heap_trim(size_t pad)
Attempts to release memory back to the system, if possible.
static size_t get_ptr_size(void *ptr)
Given a pointer that was returned by a MemoryHook allocation, returns the number of bytes that were a...