max-heap-size

This commit is contained in:
David Rose 2007-11-20 22:13:03 +00:00
parent c9201caa41
commit c11e8411d9
5 changed files with 147 additions and 31 deletions

View File

@ -135,6 +135,7 @@ MemoryHook() {
_total_heap_array_size = 0; _total_heap_array_size = 0;
_requested_heap_size = 0; _requested_heap_size = 0;
_total_mmap_size = 0; _total_mmap_size = 0;
_max_heap_size = ~(size_t)0;
#endif #endif
} }
@ -152,6 +153,7 @@ MemoryHook(const MemoryHook &copy) :
_total_heap_array_size = copy._total_heap_array_size; _total_heap_array_size = copy._total_heap_array_size;
_requested_heap_size = copy._requested_heap_size; _requested_heap_size = copy._requested_heap_size;
_total_mmap_size = copy._total_mmap_size; _total_mmap_size = copy._total_mmap_size;
_max_heap_size = copy._max_heap_size;
#endif #endif
((MutexImpl &)copy._lock).lock(); ((MutexImpl &)copy._lock).lock();
@ -183,12 +185,6 @@ MemoryHook::
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void *MemoryHook:: void *MemoryHook::
heap_alloc_single(size_t size) { heap_alloc_single(size_t size) {
#ifdef DO_MEMORY_USAGE
// In the DO_MEMORY_USAGE case, we want to track the total size of
// allocated bytes on the heap.
AtomicAdjust::add(_total_heap_single_size, (PN_int32)size);
#endif // DO_MEMORY_USAGE
#ifdef MEMORY_HOOK_MALLOC_LOCK #ifdef MEMORY_HOOK_MALLOC_LOCK
_lock.lock(); _lock.lock();
void *alloc = call_malloc(inflate_size(size)); void *alloc = call_malloc(inflate_size(size));
@ -202,6 +198,17 @@ heap_alloc_single(size_t size) {
abort(); abort();
} }
#ifdef DO_MEMORY_USAGE
// In the DO_MEMORY_USAGE case, we want to track the total size of
// allocated bytes on the heap.
AtomicAdjust::add(_total_heap_single_size, (PN_int32)size);
if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
(size_t)AtomicAdjust::get(_total_heap_array_size) >
_max_heap_size) {
overflow_heap_size();
}
#endif // DO_MEMORY_USAGE
return alloc_to_ptr(alloc, size); return alloc_to_ptr(alloc, size);
} }
@ -244,12 +251,6 @@ heap_free_single(void *ptr) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void *MemoryHook:: void *MemoryHook::
heap_alloc_array(size_t size) { heap_alloc_array(size_t size) {
#ifdef DO_MEMORY_USAGE
// In the DO_MEMORY_USAGE case, we want to track the total size of
// allocated bytes on the heap.
AtomicAdjust::add(_total_heap_array_size, (PN_int32)size);
#endif // DO_MEMORY_USAGE
#ifdef MEMORY_HOOK_MALLOC_LOCK #ifdef MEMORY_HOOK_MALLOC_LOCK
_lock.lock(); _lock.lock();
void *alloc = call_malloc(inflate_size(size)); void *alloc = call_malloc(inflate_size(size));
@ -263,6 +264,17 @@ heap_alloc_array(size_t size) {
abort(); abort();
} }
#ifdef DO_MEMORY_USAGE
// In the DO_MEMORY_USAGE case, we want to track the total size of
// allocated bytes on the heap.
AtomicAdjust::add(_total_heap_array_size, (PN_int32)size);
if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
(size_t)AtomicAdjust::get(_total_heap_array_size) >
_max_heap_size) {
overflow_heap_size();
}
#endif // DO_MEMORY_USAGE
return alloc_to_ptr(alloc, size); return alloc_to_ptr(alloc, size);
} }
@ -490,3 +502,21 @@ get_deleted_chain(size_t buffer_size) {
_lock.release(); _lock.release();
return chain; return chain;
} }
#ifdef DO_MEMORY_USAGE
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::overflow_heap_size
// Access: Protected, Virtual
// Description: This callback method is called whenever the total
// allocated heap size exceeds _max_heap_size. It's
// mainly intended for reporting memory leaks, on the
// assumption that once we cross some specified
// threshold, we're just leaking memory.
//
// The implementation for this method is in MemoryUsage.
////////////////////////////////////////////////////////////////////
void MemoryHook::
overflow_heap_size() {
_max_heap_size = ~(size_t)0;
}
#endif // DO_MEMORY_USAGE

View File

@ -82,7 +82,13 @@ protected:
TVOLATILE PN_int32 _total_heap_array_size; TVOLATILE PN_int32 _total_heap_array_size;
TVOLATILE PN_int32 _requested_heap_size; TVOLATILE PN_int32 _requested_heap_size;
TVOLATILE PN_int32 _total_mmap_size; TVOLATILE PN_int32 _total_mmap_size;
#endif
// If the allocated heap size crosses this threshold, we call
// overflow_heap_size().
size_t _max_heap_size;
virtual void overflow_heap_size();
#endif // DO_MEMORY_USAGE
private: private:
size_t _page_size; size_t _page_size;

View File

@ -137,7 +137,7 @@ get_total_cpp_size() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage:: INLINE size_t MemoryUsage::
get_panda_heap_single_size() { get_panda_heap_single_size() {
return get_global_ptr()->_total_heap_single_size; return AtomicAdjust::get(get_global_ptr()->_total_heap_single_size);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -148,7 +148,7 @@ get_panda_heap_single_size() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage:: INLINE size_t MemoryUsage::
get_panda_heap_array_size() { get_panda_heap_array_size() {
return get_global_ptr()->_total_heap_array_size; return AtomicAdjust::get(get_global_ptr()->_total_heap_array_size);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -163,7 +163,7 @@ INLINE size_t MemoryUsage::
get_panda_heap_overhead() { get_panda_heap_overhead() {
#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
MemoryUsage *mu = get_global_ptr(); MemoryUsage *mu = get_global_ptr();
return mu->_requested_heap_size - mu->_total_heap_single_size - mu->_total_heap_array_size; return AtomicAdjust::get(mu->_requested_heap_size) - AtomicAdjust::get(mu->_total_heap_single_size) - AtomicAdjust::get(mu->_total_heap_array_size);
#else #else
return 0; return 0;
#endif #endif
@ -177,7 +177,7 @@ get_panda_heap_overhead() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage:: INLINE size_t MemoryUsage::
get_panda_mmap_size() { get_panda_mmap_size() {
return get_global_ptr()->_total_mmap_size; return AtomicAdjust::get(get_global_ptr()->_total_mmap_size);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -246,7 +246,7 @@ get_total_size() {
#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) #if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
return mu->_requested_heap_size; return mu->_requested_heap_size;
#else #else
return mu->_total_heap_single_size + mu->_total_heap_array_size; return AtomicAdjust::get(mu->_total_heap_single_size) + AtomicAdjust::get(mu->_total_heap_array_size);
#endif #endif
} }
} }

View File

@ -382,8 +382,34 @@ MemoryUsage(const MemoryHook &copy) : MemoryHook(copy) {
PRC_DESC("Set this to true to enable full-force tracking of C++ allocations " PRC_DESC("Set this to true to enable full-force tracking of C++ allocations "
"and recordkeeping by type. It's quite expensive.")); "and recordkeeping by type. It's quite expensive."));
// Since enabling this after startup might cause bogus errors, we'd
// like to know if this happened, so we can squelch those error
// messages.
_startup_track_memory_usage = _track_memory_usage;
_report_memory_usage = ConfigVariableBool
("report-memory-usage", false,
PRC_DESC("Set this true to enable automatic reporting of allocated objects "
"at the interval specified by report-memory-interval. This also "
"requires track-memory-usage."));
_report_memory_interval = ConfigVariableDouble
("report-memory-interval", 5.0,
PRC_DESC("This is the interval, in seconds, for reports of currently allocated "
"memory, when report-memory-usage is true."));
_last_report_time = 0.0;
_count_memory_usage = false; _count_memory_usage = false;
int max_heap_size = ConfigVariableInt
("max-heap-size", 0,
PRC_DESC("If this is nonzero, it is the maximum number of bytes expected "
"to be allocated on the heap before we enter report-memory-usage "
"mode automatically. The assumption is that once this limit "
"has been crossed, we must be leaking."));
if (max_heap_size != 0) {
_max_heap_size = (size_t)max_heap_size;
}
#ifdef USE_MEMORY_NOWRAPPERS #ifdef USE_MEMORY_NOWRAPPERS
#error Cannot compile MemoryUsage without malloc wrappers! #error Cannot compile MemoryUsage without malloc wrappers!
#endif #endif
@ -405,6 +431,37 @@ MemoryUsage(const MemoryHook &copy) : MemoryHook(copy) {
_total_size = 0; _total_size = 0;
} }
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::overflow_heap_size
// Access: Protected, Virtual
// Description: This callback method is called whenever the total
// allocated heap size exceeds _max_heap_size. It's
// mainly intended for reporting memory leaks, on the
// assumption that once we cross some specified
// threshold, we're just leaking memory.
////////////////////////////////////////////////////////////////////
void MemoryUsage::
overflow_heap_size() {
MemoryHook::overflow_heap_size();
express_cat.error()
<< "Total allocated memory has reached "
<< get_panda_heap_single_size() + get_panda_heap_array_size()
<< " bytes."
<< "\n heap single: " << get_panda_heap_single_size()
<< "\n heap array: " << get_panda_heap_array_size()
<< "\n heap overhead: " << get_panda_heap_overhead()
<< "\n mmap: " << get_panda_mmap_size()
<< "\n interpreter: " << get_interpreter_size()
<< "\n external: " << get_external_size()
<< "\n total: " << get_total_size()
<< "\n";
// Turn on spamful debugging.
_track_memory_usage = true;
_report_memory_usage = true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::get_global_ptr // Function: MemoryUsage::get_global_ptr
// Access: Private, Static // Access: Private, Static
@ -464,6 +521,16 @@ ns_record_pointer(ReferenceCount *ptr) {
// that we also protect ourselves against a possible recursive // that we also protect ourselves against a possible recursive
// call in TrueClock::get_global_ptr(). // call in TrueClock::get_global_ptr().
_recursion_protect = false; _recursion_protect = false;
if (_report_memory_usage) {
double now = TrueClock::get_global_ptr()->get_long_time();
if (now - _last_report_time > _report_memory_interval) {
_last_report_time = now;
express_cat.info()
<< "*** Current memory usage: " << get_total_size() << "\n";
show_current_types();
}
}
} }
} }
@ -482,10 +549,12 @@ ns_update_type(ReferenceCount *ptr, TypeHandle type) {
Table::iterator ti; Table::iterator ti;
ti = _table.find(ptr); ti = _table.find(ptr);
if (ti == _table.end()) { if (ti == _table.end()) {
express_cat.error() if (_startup_track_memory_usage) {
<< "Attempt to update type to " << type << " for unrecorded pointer " express_cat.error()
<< (void *)ptr << "!\n"; << "Attempt to update type to " << type << " for unrecorded pointer "
nassertv(false); << (void *)ptr << "!\n";
nassertv(false);
}
return; return;
} }
@ -514,10 +583,12 @@ ns_update_type(ReferenceCount *ptr, TypedObject *typed_ptr) {
Table::iterator ti; Table::iterator ti;
ti = _table.find(ptr); ti = _table.find(ptr);
if (ti == _table.end()) { if (ti == _table.end()) {
express_cat.error() if (_startup_track_memory_usage) {
<< "Attempt to update type to " << typed_ptr->get_type() express_cat.error()
<< " for unrecorded pointer " << "Attempt to update type to " << typed_ptr->get_type()
<< (void *)ptr << "!\n"; << " for unrecorded pointer "
<< (void *)ptr << "!\n";
}
return; return;
} }
@ -541,11 +612,13 @@ ns_remove_pointer(ReferenceCount *ptr) {
Table::iterator ti; Table::iterator ti;
ti = _table.find(ptr); ti = _table.find(ptr);
if (ti == _table.end()) { if (ti == _table.end()) {
express_cat.error() if (_startup_track_memory_usage) {
<< "Attempt to remove pointer " << (void *)ptr express_cat.error()
<< ", not in table.\n" << "Attempt to remove pointer " << (void *)ptr
<< "Possibly a double-destruction.\n"; << ", not in table.\n"
nassertv(false); << "Possibly a double-destruction.\n";
nassertv(false);
}
return; return;
} }

View File

@ -91,6 +91,9 @@ PUBLISHED:
INLINE static void show_current_ages(); INLINE static void show_current_ages();
INLINE static void show_trend_ages(); INLINE static void show_trend_ages();
protected:
virtual void overflow_heap_size();
private: private:
MemoryUsage(const MemoryHook &copy); MemoryUsage(const MemoryHook &copy);
static MemoryUsage *get_global_ptr(); static MemoryUsage *get_global_ptr();
@ -183,7 +186,11 @@ private:
bool _track_memory_usage; bool _track_memory_usage;
bool _startup_track_memory_usage;
bool _count_memory_usage; bool _count_memory_usage;
bool _report_memory_usage;
double _report_memory_interval;
double _last_report_time;
static bool _recursion_protect; static bool _recursion_protect;
}; };