mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-05 03:15:07 -04:00
fix memory leak
This commit is contained in:
parent
5abe3a9e1c
commit
36dfcf2437
@ -17,16 +17,11 @@
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
TVOLATILE TYPENAME DeletedChain<Type>::ObjectNode * TVOLATILE DeletedChain<Type>::_deleted_chain;
|
DeletedChain<Type> StaticDeletedChain<Type>::_chain;
|
||||||
|
|
||||||
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
|
||||||
template<class Type>
|
|
||||||
MutexImpl *DeletedChain<Type>::_lock;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: DeletedChain::allocate
|
// Function: DeletedChain::allocate
|
||||||
// Access: Public, Static
|
// Access: Public
|
||||||
// Description: Allocates the memory for a new object of Type.
|
// Description: Allocates the memory for a new object of Type.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
template<class Type>
|
template<class Type>
|
||||||
@ -232,7 +227,7 @@ type_to_node(Type *ptr) {
|
|||||||
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: DeletedChain::init_lock
|
// Function: DeletedChain::init_lock
|
||||||
// Access: Private, Static
|
// Access: Private
|
||||||
// Description: Ensures the lock pointer has been allocated.
|
// Description: Ensures the lock pointer has been allocated.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
template<class Type>
|
template<class Type>
|
||||||
@ -247,7 +242,7 @@ init_lock() {
|
|||||||
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: DeletedChain::do_init_lock
|
// Function: DeletedChain::do_init_lock
|
||||||
// Access: Private, Static
|
// Access: Private
|
||||||
// Description: Allocates the lock pointer if necessary. Takes some
|
// Description: Allocates the lock pointer if necessary. Takes some
|
||||||
// pains to protect itself from race conditions.
|
// pains to protect itself from race conditions.
|
||||||
//
|
//
|
||||||
@ -275,3 +270,41 @@ do_init_lock(MutexImpl *&lock) {
|
|||||||
assert(lock != (MutexImpl *)NULL);
|
assert(lock != (MutexImpl *)NULL);
|
||||||
}
|
}
|
||||||
#endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
#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);
|
||||||
|
}
|
||||||
|
@ -82,10 +82,10 @@ enum DeletedChainFlag {
|
|||||||
template<class Type>
|
template<class Type>
|
||||||
class DeletedChain {
|
class DeletedChain {
|
||||||
public:
|
public:
|
||||||
INLINE static Type *allocate(size_t size, TypeHandle type_handle);
|
INLINE Type *allocate(size_t size, TypeHandle type_handle);
|
||||||
INLINE static void deallocate(Type *ptr, 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:
|
private:
|
||||||
class ObjectNode {
|
class ObjectNode {
|
||||||
@ -105,44 +105,92 @@ private:
|
|||||||
TVOLATILE ObjectNode * TVOLATILE _next;
|
TVOLATILE ObjectNode * TVOLATILE _next;
|
||||||
};
|
};
|
||||||
|
|
||||||
INLINE static Type *node_to_type(TVOLATILE ObjectNode *node);
|
static INLINE Type *node_to_type(TVOLATILE ObjectNode *node);
|
||||||
INLINE static ObjectNode *type_to_node(Type *ptr);
|
static INLINE ObjectNode *type_to_node(Type *ptr);
|
||||||
|
|
||||||
// Ideally, the compiler and linker will unify all references to
|
TVOLATILE ObjectNode * TVOLATILE _deleted_chain;
|
||||||
// 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;
|
|
||||||
|
|
||||||
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
|
||||||
// If we don't have atomic compare-and-exchange, we need to use a
|
// If we don't have atomic compare-and-exchange, we need to use a
|
||||||
// Mutex to protect the above linked list.
|
// Mutex to protect the above linked list.
|
||||||
static INLINE void init_lock();
|
INLINE void init_lock();
|
||||||
static void do_init_lock(MutexImpl *&lock);
|
void do_init_lock(MutexImpl *&lock);
|
||||||
static MutexImpl *_lock;
|
MutexImpl *_lock;
|
||||||
#endif
|
#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
|
// Place this macro within a class definition to define appropriate
|
||||||
// operator new and delete methods that take advantage of
|
// operator new and delete methods that take advantage of
|
||||||
// DeletedChain.
|
// DeletedChain.
|
||||||
#define ALLOC_DELETED_CHAIN(Type) \
|
#define ALLOC_DELETED_CHAIN(Type) \
|
||||||
inline void *operator new(size_t size) { \
|
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) { \
|
inline void *operator new(size_t size, void *ptr) { \
|
||||||
return ptr; \
|
return ptr; \
|
||||||
} \
|
} \
|
||||||
inline void operator delete(void *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 void operator delete(void *, void *) { \
|
||||||
} \
|
} \
|
||||||
inline static bool validate_ptr(const void *ptr) { \
|
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"
|
#include "deletedChain.T"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,14 +29,14 @@ allocate(TYPENAME pallocator_single<Type>::size_type n, TYPENAME allocator<void>
|
|||||||
TAU_PROFILE("pallocator_single:allocate()", " ", TAU_USER);
|
TAU_PROFILE("pallocator_single:allocate()", " ", TAU_USER);
|
||||||
// This doesn't support allocating arrays.
|
// This doesn't support allocating arrays.
|
||||||
assert(n == 1);
|
assert(n == 1);
|
||||||
return DeletedChain<Type>::allocate(sizeof(Type), _type_handle);
|
return StaticDeletedChain<Type>::allocate(sizeof(Type), _type_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
INLINE void pallocator_single<Type>::
|
INLINE void pallocator_single<Type>::
|
||||||
deallocate(TYPENAME pallocator_single<Type>::pointer p, TYPENAME pallocator_single<Type>::size_type) {
|
deallocate(TYPENAME pallocator_single<Type>::pointer p, TYPENAME pallocator_single<Type>::size_type) {
|
||||||
TAU_PROFILE("pallocator_single:deallocate()", " ", TAU_USER);
|
TAU_PROFILE("pallocator_single:deallocate()", " ", TAU_USER);
|
||||||
return DeletedChain<Type>::deallocate(p, _type_handle);
|
StaticDeletedChain<Type>::deallocate(p, _type_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
|
@ -53,6 +53,8 @@ TypeHandle GeomVertexArrayData::_type_handle;
|
|||||||
TypeHandle GeomVertexArrayData::CData::_type_handle;
|
TypeHandle GeomVertexArrayData::CData::_type_handle;
|
||||||
TypeHandle GeomVertexArrayDataHandle::_type_handle;
|
TypeHandle GeomVertexArrayDataHandle::_type_handle;
|
||||||
|
|
||||||
|
ALLOC_DELETED_CHAIN_DEF(GeomVertexArrayDataHandle);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomVertexArrayData::Default Constructor
|
// Function: GeomVertexArrayData::Default Constructor
|
||||||
// Access: Private
|
// Access: Private
|
||||||
|
@ -252,7 +252,7 @@ PUBLISHED:
|
|||||||
INLINE ~GeomVertexArrayDataHandle();
|
INLINE ~GeomVertexArrayDataHandle();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ALLOC_DELETED_CHAIN(GeomVertexArrayDataHandle);
|
ALLOC_DELETED_CHAIN_DECL(GeomVertexArrayDataHandle);
|
||||||
|
|
||||||
INLINE Thread *get_current_thread() const;
|
INLINE Thread *get_current_thread() const;
|
||||||
INLINE const GeomVertexArrayData *get_object() const;
|
INLINE const GeomVertexArrayData *get_object() const;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user