瀏覽代碼

fix memory leak

David Rose 18 年之前
父節點
當前提交
36dfcf2437

+ 42 - 9
dtool/src/dtoolbase/deletedChain.T

@@ -17,16 +17,11 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 template<class Type>
 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
 //     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);
+}

+ 66 - 18
dtool/src/dtoolbase/deletedChain.h

@@ -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 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:
 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);
-  INLINE static 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;
+  static INLINE Type *node_to_type(TVOLATILE ObjectNode *node);
+  static INLINE ObjectNode *type_to_node(Type *ptr);
 
 
+  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();
-  static void do_init_lock(MutexImpl *&lock);
-  static MutexImpl *_lock;
+  INLINE void init_lock();
+  void do_init_lock(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

+ 2 - 2
dtool/src/dtoolbase/pallocator.T

@@ -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>

+ 2 - 0
panda/src/gobj/geomVertexArrayData.cxx

@@ -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

+ 1 - 1
panda/src/gobj/geomVertexArrayData.h

@@ -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;