fix memory leak

This commit is contained in:
David Rose 2007-06-03 20:16:00 +00:00
parent 5abe3a9e1c
commit 36dfcf2437
5 changed files with 113 additions and 30 deletions

View File

@ -17,16 +17,11 @@
////////////////////////////////////////////////////////////////////
template<class Type>
TVOLATILE TYPENAME DeletedChain<Type>::ObjectNode * TVOLATILE DeletedChain<Type>::_deleted_chain;
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
template<class Type>
MutexImpl *DeletedChain<Type>::_lock;
#endif
DeletedChain<Type> StaticDeletedChain<Type>::_chain;
////////////////////////////////////////////////////////////////////
// Function: DeletedChain::allocate
// Access: Public, Static
// Access: Public
// Description: Allocates the memory for a new object of Type.
////////////////////////////////////////////////////////////////////
template<class Type>
@ -232,7 +227,7 @@ type_to_node(Type *ptr) {
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
////////////////////////////////////////////////////////////////////
// Function: DeletedChain::init_lock
// Access: Private, Static
// Access: Private
// Description: Ensures the lock pointer has been allocated.
////////////////////////////////////////////////////////////////////
template<class Type>
@ -247,7 +242,7 @@ init_lock() {
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
////////////////////////////////////////////////////////////////////
// Function: DeletedChain::do_init_lock
// Access: Private, Static
// Access: Private
// Description: Allocates the lock pointer if necessary. Takes some
// pains to protect itself from race conditions.
//
@ -275,3 +270,41 @@ do_init_lock(MutexImpl *&lock) {
assert(lock != (MutexImpl *)NULL);
}
#endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
////////////////////////////////////////////////////////////////////
// Function: StaticDeletedChain::allocate
// Access: Public, Static
// Description: Allocates the memory for a new object of Type.
////////////////////////////////////////////////////////////////////
template<class Type>
INLINE Type *StaticDeletedChain<Type>::
allocate(size_t size, TypeHandle type_handle) {
return _chain.allocate(size, type_handle);
}
////////////////////////////////////////////////////////////////////
// Function: StaticDeletedChain::deallocate
// Access: Public
// Description: Frees the memory for an object of Type.
////////////////////////////////////////////////////////////////////
template<class Type>
INLINE void StaticDeletedChain<Type>::
deallocate(Type *ptr, TypeHandle type_handle) {
_chain.deallocate(ptr, type_handle);
}
////////////////////////////////////////////////////////////////////
// Function: StaticDeletedChain::validate
// Access: Public
// Description: Returns true if the pointer is valid, false if it has
// been deleted or if it was never a valid pointer.
//
// This is only meaningful in debug mode, where
// USE_DELETEDCHAINFLAG is defined. If not, this
// trivially returns true.
////////////////////////////////////////////////////////////////////
template<class Type>
INLINE bool StaticDeletedChain<Type>::
validate(const Type *ptr) {
return _chain.validate(ptr);
}

View File

@ -82,10 +82,10 @@ enum DeletedChainFlag {
template<class Type>
class DeletedChain {
public:
INLINE static Type *allocate(size_t size, TypeHandle type_handle);
INLINE static void deallocate(Type *ptr, TypeHandle type_handle);
INLINE Type *allocate(size_t size, TypeHandle type_handle);
INLINE void deallocate(Type *ptr, TypeHandle type_handle);
INLINE static bool validate(const Type *ptr);
INLINE bool validate(const Type *ptr);
private:
class ObjectNode {
@ -105,44 +105,92 @@ private:
TVOLATILE ObjectNode * TVOLATILE _next;
};
INLINE static Type *node_to_type(TVOLATILE ObjectNode *node);
INLINE static ObjectNode *type_to_node(Type *ptr);
static INLINE Type *node_to_type(TVOLATILE ObjectNode *node);
static INLINE ObjectNode *type_to_node(Type *ptr);
// Ideally, the compiler and linker will unify all references to
// this static pointer for a given type, as per the C++ spec.
// However, if the compiler fails to do this (*cough* Microsoft), it
// won't be a big deal; it just means there will be multiple
// unrelated chains of deleted objects for a particular type.
static TVOLATILE ObjectNode * TVOLATILE _deleted_chain;
TVOLATILE ObjectNode * TVOLATILE _deleted_chain;
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
// If we don't have atomic compare-and-exchange, we need to use a
// Mutex to protect the above linked list.
static INLINE void init_lock();
static void do_init_lock(MutexImpl *&lock);
static MutexImpl *_lock;
INLINE void init_lock();
void do_init_lock(MutexImpl *&lock);
MutexImpl *_lock;
#endif
};
////////////////////////////////////////////////////////////////////
// Class : StaticDeletedChain
// Description : This template class is used to conveniently
// declare a single instance of the DeletedChain
// template object, above, for a particular type.
//
// It relies on the fact that the compiler and linker
// should unify all references to this static pointer
// for a given type, as per the C++ spec. However, this
// sometimes fails; and if the compiler fails to do
// this, it mostly won't be a big deal; it just means
// there will be multiple unrelated chains of deleted
// objects for a particular type. This is only a
// problem if the code structure causes objects to be
// allocated from one chain and freed to another, which
// can lead to leaks.
////////////////////////////////////////////////////////////////////
template<class Type>
class StaticDeletedChain {
public:
INLINE static Type *allocate(size_t size, TypeHandle type_handle);
INLINE static void deallocate(Type *ptr, TypeHandle type_handle);
INLINE static bool validate(const Type *ptr);
static DeletedChain<Type> _chain;
};
// Place this macro within a class definition to define appropriate
// operator new and delete methods that take advantage of
// DeletedChain.
#define ALLOC_DELETED_CHAIN(Type) \
inline void *operator new(size_t size) { \
return (void *)DeletedChain< Type >::allocate(size, get_type_handle(Type)); \
return (void *)StaticDeletedChain< Type >::allocate(size, get_type_handle(Type)); \
} \
inline void *operator new(size_t size, void *ptr) { \
return ptr; \
} \
inline void operator delete(void *ptr) { \
DeletedChain< Type >::deallocate((Type *)ptr, get_type_handle(Type)); \
StaticDeletedChain< Type >::deallocate((Type *)ptr, get_type_handle(Type)); \
} \
inline void operator delete(void *, void *) { \
} \
inline static bool validate_ptr(const void *ptr) { \
return DeletedChain< Type >::validate((const Type *)ptr); \
return StaticDeletedChain< Type >::validate((const Type *)ptr); \
}
// Use this variant of the above macro in cases in which the compiler
// fails to unify the static template pointers properly, to prevent
// leaks.
#define ALLOC_DELETED_CHAIN_DECL(Type) \
inline void *operator new(size_t size) { \
return (void *)_deleted_chain.allocate(size, get_type_handle(Type)); \
} \
inline void *operator new(size_t size, void *ptr) { \
return ptr; \
} \
inline void operator delete(void *ptr) { \
_deleted_chain.deallocate((Type *)ptr, get_type_handle(Type)); \
} \
inline void operator delete(void *, void *) { \
} \
inline static bool validate_ptr(const void *ptr) { \
return _deleted_chain.validate((const Type *)ptr); \
} \
static DeletedChain< Type > _deleted_chain;
// When you use ALLOC_DELETED_CHAIN_DECL in a class body, you must
// also put this line in the .cxx file defining that class body.
#define ALLOC_DELETED_CHAIN_DEF(Type) \
DeletedChain< Type > Type::_deleted_chain;
#include "deletedChain.T"
#endif

View File

@ -29,14 +29,14 @@ allocate(TYPENAME pallocator_single<Type>::size_type n, TYPENAME allocator<void>
TAU_PROFILE("pallocator_single:allocate()", " ", TAU_USER);
// This doesn't support allocating arrays.
assert(n == 1);
return DeletedChain<Type>::allocate(sizeof(Type), _type_handle);
return StaticDeletedChain<Type>::allocate(sizeof(Type), _type_handle);
}
template<class Type>
INLINE void pallocator_single<Type>::
deallocate(TYPENAME pallocator_single<Type>::pointer p, TYPENAME pallocator_single<Type>::size_type) {
TAU_PROFILE("pallocator_single:deallocate()", " ", TAU_USER);
return DeletedChain<Type>::deallocate(p, _type_handle);
StaticDeletedChain<Type>::deallocate(p, _type_handle);
}
template<class Type>

View File

@ -53,6 +53,8 @@ TypeHandle GeomVertexArrayData::_type_handle;
TypeHandle GeomVertexArrayData::CData::_type_handle;
TypeHandle GeomVertexArrayDataHandle::_type_handle;
ALLOC_DELETED_CHAIN_DEF(GeomVertexArrayDataHandle);
////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayData::Default Constructor
// Access: Private

View File

@ -252,7 +252,7 @@ PUBLISHED:
INLINE ~GeomVertexArrayDataHandle();
public:
ALLOC_DELETED_CHAIN(GeomVertexArrayDataHandle);
ALLOC_DELETED_CHAIN_DECL(GeomVertexArrayDataHandle);
INLINE Thread *get_current_thread() const;
INLINE const GeomVertexArrayData *get_object() const;