15 #include "memoryHook.h"
16 #include "deletedBufferChain.h"
22 #ifndef WIN32_LEAN_AND_MEAN
23 #define WIN32_LEAN_AND_MEAN 1
31 #include <sys/types.h>
35 #define MAP_ANON 0x1000
41 #if defined(USE_MEMORY_DLMALLOC)
52 #define USE_DL_PREFIX 1
62 #include "dlmalloc_src.cxx"
64 #define call_malloc dlmalloc
65 #define call_realloc dlrealloc
66 #define call_free dlfree
67 #define MEMORY_HOOK_MALLOC_LOCK 1
69 #elif defined(USE_MEMORY_PTMALLOC2)
86 #define USE_DL_PREFIX 1
89 #define MALLOC_DEBUG 2
91 #include "ptmalloc2_smp_src.cxx"
93 #define call_malloc dlmalloc
94 #define call_realloc dlrealloc
95 #define call_free dlfree
96 #undef MEMORY_HOOK_MALLOC_LOCK
109 #define call_malloc malloc
110 #define call_realloc realloc
111 #define call_free free
112 #undef MEMORY_HOOK_MALLOC_LOCK
114 #endif // USE_MEMORY_*
127 GetSystemInfo(&sysinfo);
129 _page_size = (size_t)sysinfo.dwPageSize;
134 _page_size = sysconf(_SC_PAGESIZE);
138 #ifdef DO_MEMORY_USAGE
139 _total_heap_single_size = 0;
140 _total_heap_array_size = 0;
141 _requested_heap_size = 0;
142 _total_mmap_size = 0;
143 _max_heap_size = ~(size_t)0;
154 _page_size(copy._page_size)
156 #ifdef DO_MEMORY_USAGE
157 _total_heap_single_size = copy._total_heap_single_size;
158 _total_heap_array_size = copy._total_heap_array_size;
159 _requested_heap_size = copy._requested_heap_size;
160 _total_mmap_size = copy._total_mmap_size;
161 _max_heap_size = copy._max_heap_size;
165 _deleted_chains = copy._deleted_chains;
193 size_t inflated_size = inflate_size(size);
195 #ifdef MEMORY_HOOK_MALLOC_LOCK
197 void *alloc = call_malloc(inflated_size);
200 void *alloc = call_malloc(inflated_size);
203 while (alloc == (
void *)NULL) {
205 #ifdef MEMORY_HOOK_MALLOC_LOCK
207 alloc = call_malloc(inflated_size);
210 alloc = call_malloc(inflated_size);
214 #ifdef DO_MEMORY_USAGE
221 overflow_heap_size();
223 #endif // DO_MEMORY_USAGE
225 void *ptr = alloc_to_ptr(alloc, size);
226 assert(ptr >= alloc && (
char *)ptr + size <= (
char *)alloc + inflated_size);
239 void *alloc = ptr_to_alloc(ptr, size);
241 #ifdef DO_MEMORY_USAGE
242 assert((
int)size <= _total_heap_single_size);
244 #endif // DO_MEMORY_USAGE
246 #ifdef MEMORY_HOOK_MALLOC_LOCK
269 size_t inflated_size = inflate_size(size);
271 #ifdef MEMORY_HOOK_MALLOC_LOCK
273 void *alloc = call_malloc(inflated_size);
276 void *alloc = call_malloc(inflated_size);
279 while (alloc == (
void *)NULL) {
281 #ifdef MEMORY_HOOK_MALLOC_LOCK
283 alloc = call_malloc(inflated_size);
286 alloc = call_malloc(inflated_size);
290 #ifdef DO_MEMORY_USAGE
297 overflow_heap_size();
299 #endif // DO_MEMORY_USAGE
301 void *ptr = alloc_to_ptr(alloc, size);
302 assert(ptr >= alloc && (
char *)ptr + size <= (
char *)alloc + inflated_size);
315 void *alloc = ptr_to_alloc(ptr, orig_size);
317 #ifdef DO_MEMORY_USAGE
318 assert((AtomicAdjust::Integer)orig_size <= _total_heap_array_size);
319 AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size-(AtomicAdjust::Integer)orig_size);
320 #endif // DO_MEMORY_USAGE
322 size_t inflated_size = inflate_size(size);
324 void *alloc1 = alloc;
325 #ifdef MEMORY_HOOK_MALLOC_LOCK
327 alloc1 = call_realloc(alloc1, inflated_size);
330 alloc1 = call_realloc(alloc1, inflated_size);
333 while (alloc1 == (
void *)NULL) {
339 #ifdef MEMORY_HOOK_MALLOC_LOCK
341 alloc1 = call_realloc(alloc1, inflated_size);
344 alloc1 = call_realloc(alloc1, inflated_size);
348 void *ptr1 = alloc_to_ptr(alloc1, size);
349 assert(ptr1 >= alloc1 && (
char *)ptr1 + size <= (
char *)alloc1 + inflated_size);
350 #if defined(MEMORY_HOOK_DO_ALIGN)
353 size_t orig_delta = (
char *)ptr - (
char *)alloc;
354 size_t new_delta = (
char *)ptr1 - (
char *)alloc1;
355 if (orig_delta != new_delta) {
356 memmove((
char *)alloc1 + new_delta, (
char *)alloc1 + orig_delta, min(size, orig_size));
358 #endif // MEMORY_HOOK_DO_ALIGN
371 void *alloc = ptr_to_alloc(ptr, size);
373 #ifdef DO_MEMORY_USAGE
374 assert((
int)size <= _total_heap_array_size);
376 #endif // DO_MEMORY_USAGE
378 #ifdef MEMORY_HOOK_MALLOC_LOCK
403 bool trimmed =
false;
405 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
410 if (dlmalloc_trim(pad)) {
418 if (_heapmin() == 0) {
444 assert((size % _page_size) == 0);
446 #ifdef DO_MEMORY_USAGE
447 _total_mmap_size += size;
453 void *ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE,
454 allow_exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
455 if (ptr == (
void *)NULL) {
456 DWORD err = GetLastError();
457 cerr <<
"Couldn't allocate memory page of size " << size <<
": ";
461 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
462 NULL, err, 0, (LPTSTR)&buffer, 0, NULL);
464 cerr << (
char *)buffer <<
"\n";
466 cerr <<
"Error code " << err <<
"\n";
477 int prot = PROT_READ | PROT_WRITE;
481 void *ptr = mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
482 if (ptr == (
void *)-1) {
500 assert((size % _page_size) == 0);
502 #ifdef DO_MEMORY_USAGE
503 assert((
int)size <= _total_mmap_size);
504 _total_mmap_size -= size;
508 VirtualFree(ptr, 0, MEM_RELEASE);
542 DeletedChains::iterator dci = _deleted_chains.find(buffer_size);
543 if (dci != _deleted_chains.end()) {
544 chain = (*dci).second;
548 _deleted_chains.insert(DeletedChains::value_type(buffer_size, chain));
574 cerr <<
"Out of memory allocating " << attempted_size <<
" bytes\n";
578 #ifdef DO_MEMORY_USAGE
591 overflow_heap_size() {
592 _max_heap_size = ~(size_t)0;
594 #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.
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.
static void add(Integer &var, Integer delta)
Atomically computes var += delta.
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.
A fake mutex implementation for single-threaded applications that don't need any synchronization cont...
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.