Panda3D
memoryHook.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file memoryHook.cxx
10  * @author drose
11  * @date 2007-06-28
12  */
13 
14 #include "memoryHook.h"
15 #include "deletedBufferChain.h"
16 #include <stdlib.h>
17 #include "typeRegistry.h"
18 
19 #ifdef WIN32
20 
21 // Windows case.
22 #ifndef WIN32_LEAN_AND_MEAN
23 #define WIN32_LEAN_AND_MEAN 1
24 #endif
25 #include <windows.h>
26 
27 #else
28 
29 // Posix case.
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 
34 #ifndef MAP_ANON
35 #define MAP_ANON 0x1000
36 #endif
37 
38 #endif // WIN32
39 
40 using std::cerr;
41 
42 // Ensure we made the right decisions about the alignment size.
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");
51 
52 #if defined(CPPPARSER)
53 
54 #elif defined(USE_MEMORY_DLMALLOC)
55 
56 // Memory manager: DLMALLOC This is Doug Lea's memory manager. It is very
57 // fast, but it is not thread-safe. However, we provide thread locking within
58 // MemoryHook.
59 
60 #define DLMALLOC_EXPORT static
61 #define USE_DL_PREFIX 1
62 #define NO_MALLINFO 1
63 #ifdef _DEBUG
64  #define DEBUG 1
65 #endif
66 // dlmalloc can do the alignment we ask for.
67 #define MALLOC_ALIGNMENT MEMORY_HOOK_ALIGNMENT
68 
69 #include "dlmalloc_src.cxx"
70 
71 #define call_malloc dlmalloc
72 #define call_realloc dlrealloc
73 #define call_free dlfree
74 #define MEMORY_HOOK_MALLOC_LOCK 1
75 
76 #elif defined(USE_MEMORY_PTMALLOC2)
77 // This doesn't appear to work in Linux; perhaps it is clashing with the
78 // system library. It also doesn't appear to be thread-safe on OSX.
79 
80 /*
81  * Memory manager: PTMALLOC2 Ptmalloc2 is a derivative of Doug Lea's memory
82  * manager that was made thread-safe by Wolfram Gloger, then was ported to
83  * windows by Niall Douglas. It is not quite as fast as dlmalloc (because the
84  * thread-safety constructs take a certain amount of CPU time), but it's still
85  * much faster than the windows allocator.
86  */
87 
88 #define USE_DL_PREFIX 1
89 #define NO_MALLINFO 1
90 #ifdef _DEBUG
91  #define MALLOC_DEBUG 2
92 #endif
93 #include "ptmalloc2_smp_src.cxx"
94 
95 #define call_malloc dlmalloc
96 #define call_realloc dlrealloc
97 #define call_free dlfree
98 #undef MEMORY_HOOK_MALLOC_LOCK
99 
100 #else
101 
102 // Memory manager: MALLOC This option uses the built-in system allocator.
103 // This is a good choice on linux, but it's a terrible choice on windows.
104 
105 #define call_malloc malloc
106 #define call_realloc realloc
107 #define call_free free
108 #undef MEMORY_HOOK_MALLOC_LOCK
109 
110 #endif // USE_MEMORY_*
111 
112 /**
113  * Increments the amount of requested size as necessary to accommodate the
114  * extra data we might piggyback on each allocated block.
115  */
116 INLINE static size_t
117 inflate_size(size_t size) {
118 #if defined(MEMORY_HOOK_DO_ALIGN)
119  // If we're aligning, we need to request the header size, plus extra bytes
120  // to give us wiggle room to adjust the pointer.
121  return size + sizeof(uintptr_t) * 2 + MEMORY_HOOK_ALIGNMENT - 1;
122 #elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
123  // If we are can access the allocator's bookkeeping to figure out how many
124  // bytes were allocated, we don't need to add our own information.
125  return size;
126 #elif defined(DO_MEMORY_USAGE)
127  // If we're not aligning, but we're tracking memory allocations, we just
128  // need the header size extra (this gives us a place to store the size of
129  // the allocated block). However, we do need to make sure that any
130  // alignment guarantee is kept.
131  return size + MEMORY_HOOK_ALIGNMENT;
132 #else
133  // If we're not doing any of that, we can just allocate the precise
134  // requested amount.
135  return size;
136 #endif // DO_MEMORY_USAGE
137 }
138 
139 /**
140  * Converts an allocated pointer to a pointer returnable to the application.
141  * Stuffs size in the first n bytes of the allocated space.
142  */
143 INLINE static void *
144 alloc_to_ptr(void *alloc, size_t size) {
145 #if defined(MEMORY_HOOK_DO_ALIGN)
146  // Add room for two uintptr_t values.
147  uintptr_t *root = (uintptr_t *)((char *)alloc + sizeof(uintptr_t) * 2);
148  // Align this to the requested boundary.
149  root = (uintptr_t *)(((uintptr_t)root + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1));
150  root[-2] = size;
151  root[-1] = (uintptr_t)alloc; // Save the pointer we originally allocated.
152  return (void *)root;
153 #elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
154  return alloc;
155 #elif defined(DO_MEMORY_USAGE)
156  size_t *root = (size_t *)alloc;
157  root[0] = size;
158  return (void *)((char *)root + MEMORY_HOOK_ALIGNMENT);
159 #else
160  return alloc;
161 #endif // DO_MEMORY_USAGE
162 }
163 
164 /**
165  * Converts an application pointer back to the original allocated pointer.
166  * Extracts size from the first n bytes of the allocated space, but only if
167  * DO_MEMORY_USAGE is defined.
168  */
169 INLINE static void *
170 ptr_to_alloc(void *ptr, size_t &size) {
171 #if defined(MEMORY_HOOK_DO_ALIGN)
172  uintptr_t *root = (uintptr_t *)ptr;
173  size = root[-2];
174  return (void *)root[-1]; // Get the pointer we originally allocated.
175 #elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
176 #ifdef DO_MEMORY_USAGE
177  size = MemoryHook::get_ptr_size(ptr);
178 #endif
179  return ptr;
180 #elif defined(DO_MEMORY_USAGE)
181  size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT);
182  size = root[0];
183  return (void *)root;
184 #else
185  return ptr;
186 #endif // DO_MEMORY_USAGE
187 }
188 
189 /**
190  *
191  */
192 MemoryHook::
193 MemoryHook() {
194 #ifdef WIN32
195 
196  // Windows case.
197  SYSTEM_INFO sysinfo;
198  GetSystemInfo(&sysinfo);
199 
200  _page_size = (size_t)sysinfo.dwPageSize;
201 
202 #else
203 
204  // Posix case.
205  _page_size = sysconf(_SC_PAGESIZE);
206 
207 #endif // WIN32
208 
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;
214 }
215 
216 /**
217  *
218  */
219 MemoryHook::
220 MemoryHook(const MemoryHook &copy) :
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) {
227 
228  copy._lock.lock();
229  _deleted_chains = copy._deleted_chains;
230  copy._lock.unlock();
231 }
232 
233 /**
234  *
235  */
236 MemoryHook::
237 ~MemoryHook() {
238  // Really, we only have this destructor to shut up gcc about the virtual
239  // functions warning.
240 }
241 
242 /**
243  * Allocates a block of memory from the heap, similar to malloc(). This will
244  * never return NULL; it will abort instead if memory is not available.
245  *
246  * This particular function should be used to allocate memory for a single
247  * object, as opposed to an array. The only difference is in the bookkeeping.
248  */
249 void *MemoryHook::
250 heap_alloc_single(size_t size) {
251  size_t inflated_size = inflate_size(size);
252 
253 #ifdef MEMORY_HOOK_MALLOC_LOCK
254  _lock.lock();
255  void *alloc = call_malloc(inflated_size);
256  _lock.unlock();
257 #else
258  void *alloc = call_malloc(inflated_size);
259 #endif
260 
261  while (alloc == nullptr) {
262  alloc_fail(inflated_size);
263 #ifdef MEMORY_HOOK_MALLOC_LOCK
264  _lock.lock();
265  alloc = call_malloc(inflated_size);
266  _lock.unlock();
267 #else
268  alloc = call_malloc(inflated_size);
269 #endif
270  }
271 
272 #ifdef DO_MEMORY_USAGE
273  // In the DO_MEMORY_USAGE case, we want to track the total size of allocated
274  // bytes on the heap.
275 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
276  // dlmalloc may slightly overallocate, however.
277  size = get_ptr_size(alloc);
278  inflated_size = size;
279 #endif
280  AtomicAdjust::add(_total_heap_single_size, (AtomicAdjust::Integer)size);
281  if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
282  (size_t)AtomicAdjust::get(_total_heap_array_size) >
283  _max_heap_size) {
284  overflow_heap_size();
285  }
286 #endif // DO_MEMORY_USAGE
287 
288  void *ptr = alloc_to_ptr(alloc, size);
289 #ifdef _DEBUG
290  assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
291  assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
292 #endif
293  return ptr;
294 }
295 
296 /**
297  * Releases a block of memory previously allocated via heap_alloc_single.
298  */
299 void MemoryHook::
300 heap_free_single(void *ptr) {
301  size_t size;
302  void *alloc = ptr_to_alloc(ptr, size);
303 
304 #ifdef DO_MEMORY_USAGE
305  assert((int)size <= _total_heap_single_size);
306  AtomicAdjust::add(_total_heap_single_size, -(AtomicAdjust::Integer)size);
307 #endif // DO_MEMORY_USAGE
308 
309 #ifdef MEMORY_HOOK_MALLOC_LOCK
310  _lock.lock();
311  call_free(alloc);
312  _lock.unlock();
313 #else
314  call_free(alloc);
315 #endif
316 }
317 
318 /**
319  * Allocates a block of memory from the heap, similar to malloc(). This will
320  * never return NULL; it will abort instead if memory is not available.
321  *
322  * This particular function should be used to allocate memory for an array of
323  * objects, as opposed to a single object. The only difference is in the
324  * bookkeeping.
325  */
326 void *MemoryHook::
327 heap_alloc_array(size_t size) {
328  size_t inflated_size = inflate_size(size);
329 
330 #ifdef MEMORY_HOOK_MALLOC_LOCK
331  _lock.lock();
332  void *alloc = call_malloc(inflated_size);
333  _lock.unlock();
334 #else
335  void *alloc = call_malloc(inflated_size);
336 #endif
337 
338  while (alloc == nullptr) {
339  alloc_fail(inflated_size);
340 #ifdef MEMORY_HOOK_MALLOC_LOCK
341  _lock.lock();
342  alloc = call_malloc(inflated_size);
343  _lock.unlock();
344 #else
345  alloc = call_malloc(inflated_size);
346 #endif
347  }
348 
349 #ifdef DO_MEMORY_USAGE
350  // In the DO_MEMORY_USAGE case, we want to track the total size of allocated
351  // bytes on the heap.
352 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
353  // dlmalloc may slightly overallocate, however.
354  size = get_ptr_size(alloc);
355  inflated_size = size;
356 #endif
357  AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size);
358  if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
359  (size_t)AtomicAdjust::get(_total_heap_array_size) >
360  _max_heap_size) {
361  overflow_heap_size();
362  }
363 #endif // DO_MEMORY_USAGE
364 
365  void *ptr = alloc_to_ptr(alloc, size);
366 #ifdef _DEBUG
367  assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
368  assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
369 #endif
370  return ptr;
371 }
372 
373 /**
374  * Resizes a block of memory previously returned from heap_alloc_array.
375  */
376 void *MemoryHook::
377 heap_realloc_array(void *ptr, size_t size) {
378  size_t orig_size;
379  void *alloc = ptr_to_alloc(ptr, orig_size);
380 
381  size_t inflated_size = inflate_size(size);
382 
383  void *alloc1 = alloc;
384 #ifdef MEMORY_HOOK_MALLOC_LOCK
385  _lock.lock();
386  alloc1 = call_realloc(alloc1, inflated_size);
387  _lock.unlock();
388 #else
389  alloc1 = call_realloc(alloc1, inflated_size);
390 #endif
391 
392  while (alloc1 == nullptr) {
393  alloc_fail(inflated_size);
394 
395  // Recover the original pointer.
396  alloc1 = alloc;
397 
398 #ifdef MEMORY_HOOK_MALLOC_LOCK
399  _lock.lock();
400  alloc1 = call_realloc(alloc1, inflated_size);
401  _lock.unlock();
402 #else
403  alloc1 = call_realloc(alloc1, inflated_size);
404 #endif
405  }
406 
407 #ifdef DO_MEMORY_USAGE
408 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
409  // dlmalloc may slightly overallocate, however.
410  size = get_ptr_size(alloc1);
411  inflated_size = size;
412 #endif
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
416 
417  // Align this to the requested boundary.
418 #ifdef MEMORY_HOOK_DO_ALIGN
419  // This copies the code from alloc_to_ptr, since we can't write the size and
420  // pointer until after we have done the memmove.
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;
424 
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));
429  }
430 
431  root[-2] = size;
432  root[-1] = (uintptr_t)alloc1; // Save the pointer we originally allocated.
433 #else
434  void *ptr1 = alloc_to_ptr(alloc1, size);
435 #endif
436 
437 #ifdef _DEBUG
438  assert(ptr1 >= alloc1 && (char *)ptr1 + size <= (char *)alloc1 + inflated_size);
439  assert(((uintptr_t)ptr1 % MEMORY_HOOK_ALIGNMENT) == 0);
440 #endif
441  return ptr1;
442 }
443 
444 /**
445  * Releases a block of memory previously allocated via heap_alloc_array.
446  */
447 void MemoryHook::
448 heap_free_array(void *ptr) {
449  size_t size;
450  void *alloc = ptr_to_alloc(ptr, size);
451 
452 #ifdef DO_MEMORY_USAGE
453  assert((int)size <= _total_heap_array_size);
454  AtomicAdjust::add(_total_heap_array_size, -(AtomicAdjust::Integer)size);
455 #endif // DO_MEMORY_USAGE
456 
457 #ifdef MEMORY_HOOK_MALLOC_LOCK
458  _lock.lock();
459  call_free(alloc);
460  _lock.unlock();
461 #else
462  call_free(alloc);
463 #endif
464 }
465 
466 /**
467  * Attempts to release memory back to the system, if possible. The pad
468  * argument is the minimum amount of unused memory to keep in the heap
469  * (against future allocations). Any memory above that may be released to the
470  * system, reducing the memory size of this process. There is no guarantee
471  * that any memory may be released.
472  *
473  * Returns true if any memory was actually released, false otherwise.
474  */
475 bool MemoryHook::
476 heap_trim(size_t pad) {
477  bool trimmed = false;
478 
479 #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
480  // Since malloc_trim() isn't standard C, we can't be sure it exists on a
481  // given platform. But if we're using dlmalloc, we know we have
482  // dlmalloc_trim.
483  _lock.lock();
484  if (dlmalloc_trim(pad)) {
485  trimmed = true;
486  }
487  _lock.unlock();
488 #endif
489 
490 #ifdef WIN32
491  // Also, on Windows we have _heapmin().
492  if (_heapmin() == 0) {
493  trimmed = true;
494  }
495 #endif
496 
497  return trimmed;
498 }
499 
500 /**
501  * Allocates a raw page or pages of memory directly from the OS. This will be
502  * in a different address space from the memory allocated by heap_alloc(), and
503  * so it won't contribute to fragmentation of that memory.
504  *
505  * The allocation size must be an integer multiple of the page size. Use
506  * round_to_page_size() if there is any doubt.
507  *
508  * If allow_exec is true, the memory will be flagged so that it is legal to
509  * execute code that has been written to this memory.
510  */
511 void *MemoryHook::
512 mmap_alloc(size_t size, bool allow_exec) {
513  assert((size % _page_size) == 0);
514 
515 #ifdef DO_MEMORY_USAGE
516  _total_mmap_size += size;
517 #endif
518 
519 #ifdef WIN32
520 
521  // Windows case.
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 << ": ";
527 
528  PVOID buffer;
529  DWORD length =
530  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
531  nullptr, err, 0, (LPTSTR)&buffer, 0, nullptr);
532  if (length != 0) {
533  cerr << (char *)buffer << "\n";
534  } else {
535  cerr << "Error code " << err << "\n";
536  }
537  LocalFree(buffer);
538  abort();
539  }
540 
541  return ptr;
542 
543 #else
544 
545  // Posix case.
546  int prot = PROT_READ | PROT_WRITE;
547  if (allow_exec) {
548  prot |= PROT_EXEC;
549  }
550  void *ptr = mmap(nullptr, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
551  if (ptr == (void *)-1) {
552  perror("mmap");
553  abort();
554  }
555 
556  return ptr;
557 
558 #endif // WIN32
559 }
560 
561 /**
562  * Frees a block of memory previously allocated via mmap_alloc(). You must
563  * know how large the block was.
564  */
565 void MemoryHook::
566 mmap_free(void *ptr, size_t size) {
567  assert((size % _page_size) == 0);
568 
569 #ifdef DO_MEMORY_USAGE
570  assert((int)size <= _total_mmap_size);
571  _total_mmap_size -= size;
572 #endif
573 
574 #ifdef WIN32
575  VirtualFree(ptr, 0, MEM_RELEASE);
576 #else
577  munmap(ptr, size);
578 #endif
579 }
580 
581 /**
582  * This special method exists only to provide a callback hook into
583  * MemoryUsage. It indicates that the indicated pointer, allocated from
584  * somewhere other than a call to heap_alloc(), now contains a pointer to the
585  * indicated ReferenceCount object. If orig_size is 0, it indicates that the
586  * ReferenceCount object has been destroyed.
587  */
588 void MemoryHook::
589 mark_pointer(void *, size_t, ReferenceCount *) {
590 }
591 
592 /**
593  * Returns a pointer to a global DeletedBufferChain object suitable for
594  * allocating arrays of the indicated size. There is one unique
595  * DeletedBufferChain object for every different size.
596  */
598 get_deleted_chain(size_t buffer_size) {
599  DeletedBufferChain *chain;
600 
601  _lock.lock();
602  DeletedChains::iterator dci = _deleted_chains.find(buffer_size);
603  if (dci != _deleted_chains.end()) {
604  chain = (*dci).second;
605  } else {
606  // Once allocated, this DeletedBufferChain object is never deleted.
607  chain = new DeletedBufferChain(buffer_size);
608  _deleted_chains.insert(DeletedChains::value_type(buffer_size, chain));
609  }
610 
611  _lock.unlock();
612  return chain;
613 }
614 
615 /**
616  * This callback method is called whenever a low-level call to call_malloc()
617  * has returned NULL, indicating failure.
618  *
619  * Since this method is called very low-level, and may be in the middle of any
620  * number of critical sections, it will be difficult for this callback
621  * initiate any emergency high-level operation to make more memory available.
622  * However, this module is set up to assume that that's what this method does,
623  * and will make another alloc attempt after it returns. Probably the only
624  * sensible thing this method can do, however, is just to display a message
625  * and abort.
626  */
627 void MemoryHook::
628 alloc_fail(size_t attempted_size) {
629  cerr << "Out of memory allocating " << attempted_size << " bytes\n";
630  abort();
631 }
632 
633 /**
634  * This callback method is called whenever the total allocated heap size
635  * exceeds _max_heap_size. It's mainly intended for reporting memory leaks,
636  * on the assumption that once we cross some specified threshold, we're just
637  * leaking memory.
638  *
639  * The implementation for this method is in MemoryUsage.
640  */
641 void MemoryHook::
642 overflow_heap_size() {
643 #ifdef DO_MEMORY_USAGE
644  _max_heap_size = ~(size_t)0;
645 #endif // DO_MEMORY_USAGE
646 }
DeletedBufferChain * get_deleted_chain(size_t buffer_size)
Returns a pointer to a global DeletedBufferChain object suitable for allocating arrays of the indicat...
Definition: memoryHook.cxx:598
virtual void heap_free_array(void *ptr)
Releases a block of memory previously allocated via heap_alloc_array.
Definition: memoryHook.cxx:448
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().
Definition: memoryHook.cxx:250
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.
Definition: memoryHook.cxx:589
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().
Definition: memoryHook.cxx:566
virtual void heap_free_single(void *ptr)
Releases a block of memory previously allocated via heap_alloc_single.
Definition: memoryHook.cxx:300
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().
Definition: memoryHook.cxx:327
This class provides a wrapper around the various possible malloc schemes Panda might employ.
Definition: memoryHook.h:37
virtual void * heap_realloc_array(void *ptr, size_t size)
Resizes a block of memory previously returned from heap_alloc_array.
Definition: memoryHook.cxx:377
virtual void alloc_fail(size_t attempted_size)
This callback method is called whenever a low-level call to call_malloc() has returned NULL,...
Definition: memoryHook.cxx:628
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.
Definition: memoryHook.cxx:512
bool heap_trim(size_t pad)
Attempts to release memory back to the system, if possible.
Definition: memoryHook.cxx:476
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...
Definition: memoryHook.I:67