[omniORB] OmniORB3.01 - Reducing memory leaks - patch 1

Jeroen.Dobbelaere@MMR.be Jeroen.Dobbelaere@MMR.be
Fri, 15 Sep 2000 13:13:06 +0100


This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

------_=_NextPart_000_01C01F0E.4E0D2BC0
Content-Type: text/plain;
	charset="ISO-8859-1"

Hi everybody,

As other developers with MSVC++, I've also encountered the problem of memory
leaks which aren't leaks,
signalled by MSVC's debug library.

In stead of living with it, I've started investigating the source of those
leaks, and tried to provide a mechanism so that
'static data' will also be cleaned up when the program tries to do a nice
'shutdown'.

First step is debugging a program which just linked in the OmniORB 3.01
libraries, without calling OmniORB functionality.
Even here, we already get a good amount of memory leaks.

I'm now cleaning up my changes and I'm providing them one by one, so that
the impact of them can be verifyed and in
the hope that they can go into the main source tree.

This first patch is for 'src/lib/omniORB2/dynamic/typecode.cc' :

- it provides a function which will cleanup the static allocated data
- it provides a 'tracker' (TrackTypeCode_ptr) which will track pointers to
TypeCode objects (exceptions and interfaces),
  so that they can be destructed in reverse order.
- it provides the necessary glue, so that those functions are indeed used.

Note : this has only been tested on Windows2000/MSVC6p4 with the 'lib'
version of the libraries.
(creation of the .dll's is ok, but has not been tested)

To apply the patch :
- go to the omni/ directory
- save the attachement to a file 'patch1'
- execute 'patch -p1 < patch1'

Greetings,
--
Jeroen Dobbelaere
Software Design Engineer
Micro-Matic Research <http://www.mmr.be>


 <<patch_1.patch>> 

------_=_NextPart_000_01C01F0E.4E0D2BC0
Content-Type: application/octet-stream;
	name="patch_1.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="patch_1.patch"

diff -c5 -r omni/src/lib/omniORB2/dynamic/typecode.cc =
omni_test/src/lib/omniORB2/dynamic/typecode.cc
*** omni/src/lib/omniORB2/dynamic/typecode.cc	Thu Jul 13 16:26:02 2000
--- omni_test/src/lib/omniORB2/dynamic/typecode.cc	Fri Sep 15 12:17:43 =
2000
***************
*** 209,218 ****
--- 209,248 ----
  #ifndef NEED_DUMMY_RETURN
  #define NEED_DUMMY_RETURN
  #endif
  #endif
 =20
+ // class that tracks the created (static) exceptions, needed for =
cleanup later...
+ // use stl (easier)
+ #include <list>
+=20
+ class TrackTypeCode_ptr
+ {
+ public:
+   typedef std::list<CORBA::TypeCode_ptr> Container;
+ public:
+   TrackTypeCode_ptr() {}
+   ~TrackTypeCode_ptr() {}
+=20
+   void attach(const CORBA::TypeCode_ptr& rhs) { =
m_table.push_back(rhs); }
+=20
+   void delete_all()=20
+   {
+     for(Container::reverse_iterator it=3Dm_table.rbegin(); it !=3D =
m_table.rend(); ++it)
+       {
+ 	delete *it;
+       }
+=20
+     m_table.erase(m_table.begin(), m_table.end());
+   }
+=20
+ private:
+   Container m_table;
+ };
+=20
+=20
+=20
 =20
  CORBA::TypeCode::~TypeCode() {
    pd_magic =3D 0;
  }
 =20
***************
*** 330,343 ****
    if (CORBA::is_nil(t))  return t;
    return TypeCode_collector::duplicateRef(ToTcBase(t));
  }
 =20
 =20
  CORBA::TypeCode_ptr
  CORBA::TypeCode::_nil()
  {
-   static TypeCode* _the_nil_ptr =3D 0;
    if( !_the_nil_ptr ) {
      omni::nilRefLock().lock();
      if( !_the_nil_ptr )  _the_nil_ptr =3D new TypeCode;
      omni::nilRefLock().unlock();
    }
--- 360,388 ----
    if (CORBA::is_nil(t))  return t;
    return TypeCode_collector::duplicateRef(ToTcBase(t));
  }
 =20
 =20
+ // move _the_nil_ptr outside of CORBA::TypeCode::_nil(), so that it =
can get destructed when needed
+ // _the_nil_ptr stays only visible inside this file
+ static CORBA::TypeCode* _the_nil_ptr =3D 0;
+=20
+ // and provide a class, so that this nil pointer can be destructed =
when the program ends
+ class CleanupTypecodeNil
+ {
+ public:
+   ~CleanupTypecodeNil() { delete _the_nil_ptr; _the_nil_ptr=3D0; }
+=20
+ private:
+   static CleanupTypecodeNil local_object;
+ };
+ CleanupTypecodeNil CleanupTypecodeNil::local_object;
+=20
+=20
  CORBA::TypeCode_ptr
  CORBA::TypeCode::_nil()
  {
    if( !_the_nil_ptr ) {
      omni::nilRefLock().lock();
      if( !_the_nil_ptr )  _the_nil_ptr =3D new TypeCode;
      omni::nilRefLock().unlock();
    }
***************
*** 512,521 ****
--- 557,569 ----
  // of the typecode functionnality it is important to ensure
  // that any statically initialised data is properly constructed.
 =20
  static void check_static_data_is_initialised();
 =20
+ // track TypeCode_ptr's, for later cleanup (in reversed order)
+ static void track_typecode_ptr(const CORBA::TypeCode_ptr& rhs);
+=20
  CORBA::TypeCode_ptr
  CORBA::TypeCode::PR_struct_tc(const char* id, const char* name,
  			      const PR_structMember* members,
  			      ULong memberCount)
  {
***************
*** 587,606 ****
      // We duplicate the name and consume the type.
      new_members[i].name =3D CORBA::string_dup(members[i].name);
      new_members[i].type =3D members[i].type;
    }
 =20
!   return new TypeCode_except(CORBA::string_dup(id), =
CORBA::string_dup(name),
  			     new_members, memberCount);
  }
 =20
 =20
  CORBA::TypeCode_ptr
  CORBA::TypeCode::PR_interface_tc(const char* id, const char* name)
  {
    check_static_data_is_initialised();
!   return new TypeCode_objref(id, name);
  }
 =20
 =20
  CORBA::TypeCode_ptr
  CORBA::TypeCode::PR_string_tc(CORBA::ULong bound)
--- 635,669 ----
      // We duplicate the name and consume the type.
      new_members[i].name =3D CORBA::string_dup(members[i].name);
      new_members[i].type =3D members[i].type;
    }
 =20
!   // keep track of all exception objects that are created in this way
!   // they are kept in static pointers and will exist for the lifetime =
of the program
!   // and at the end, they will get destructed in reverse order
!   CORBA::TypeCode_ptr return_value =3D=20
!     new TypeCode_except(CORBA::string_dup(id), CORBA::string_dup(name)=
,
  			     new_members, memberCount);
+=20
+   track_typecode_ptr(return_value);
+=20
+   return return_value;
  }
 =20
 =20
  CORBA::TypeCode_ptr
  CORBA::TypeCode::PR_interface_tc(const char* id, const char* name)
  {
    check_static_data_is_initialised();
!=20
!   // keep track the generated interface pointers, they will exist for =
the lifetime of the program
!   // and at the end, they will get destructed in reverse order
!   CORBA::TypeCode_ptr return_value =3D new TypeCode_objref(id, name);
!=20
!   track_typecode_ptr(return_value);
!=20
!   return return_value;
  }
 =20
 =20
  CORBA::TypeCode_ptr
  CORBA::TypeCode::PR_string_tc(CORBA::ULong bound)
***************
*** 5322,5334 ****
  // also generate new typecodes. This is used to ensure that all
  // necassary infrastructure is properly constructed before it is
  // accessed by the stubs. This is necassary because the compiler
  // does not specify the order of initialisation.
  //
  static void check_static_data_is_initialised()
  {
!   static int is_initialised =3D 0;
 =20
    if( is_initialised )  return;
 =20
    is_initialised =3D 1;
 =20
--- 5385,5402 ----
  // also generate new typecodes. This is used to ensure that all
  // necassary infrastructure is properly constructed before it is
  // accessed by the stubs. This is necassary because the compiler
  // does not specify the order of initialisation.
  //
+=20
+ // is_initialised has been -- moved out of =
check_static_data_is_initialised
+ // so that it can be used by remove_static_data for a nice cleanup
+ static int is_initialised =3D 0;
+=20
  static void check_static_data_is_initialised()
  {
!   // static int is_initialised =3D 0;
 =20
    if( is_initialised )  return;
 =20
    is_initialised =3D 1;
 =20
***************
*** 5371,5386 ****
--- 5439,5562 ----
     =20
      CORBA::_tc_NamedValue =3D =
CORBA::TypeCode::PR_struct_tc("IDL:omg.org/CORBA/NamedValue:1.0", =
"NamedValue",nvMembers, 4);
    }
  }
 =20
+ // remove_static_data : remove the data in reverse order
+ // watch out ! some of the objects were already consumed by other =
created objectes !!
+ static void remove_static_data()
+ {
+   if(is_initialised=3D=3D0)
+     return;
+=20
+   // objects which are already delete by the exception cleanup
+   CORBA::_tc_Object=3DNULL;
+   CORBA::_tc_ulong=3DNULL;
+   CORBA::_tc_ushort=3DNULL;
+=20
+   // can cause conflicts with tc_any and tc_long
+   delete  CORBA::_tc_NamedValue;
+   CORBA::_tc_NamedValue =3D NULL;
+=20
+   // deletion of _tc_NamedValue also deletes :
+   CORBA::_tc_any =3D NULL;
+   CORBA::_tc_long =3D NULL;
+=20
+   //remove types
+   delete CORBA::_tc_string;
+   CORBA::_tc_string=3DNULL;
+  =20
+   delete CORBA::_tc_Object;
+   CORBA::_tc_Object=3DNULL;
+  =20
+   delete CORBA::_tc_Principal;
+   CORBA::_tc_Principal=3DNULL;
+  =20
+   delete CORBA::_tc_TypeCode;
+   CORBA::_tc_TypeCode=3DNULL;
+  =20
+   delete CORBA::_tc_any;
+   CORBA::_tc_any=3DNULL;
+  =20
+   delete CORBA::_tc_octet;
+   CORBA::_tc_octet=3DNULL;
+=20
+   delete CORBA::_tc_char;
+   CORBA::_tc_char=3DNULL;
+  =20
+   delete CORBA::_tc_boolean;
+   CORBA::_tc_boolean=3DNULL;
+  =20
+   delete CORBA::_tc_double;
+   CORBA::_tc_double=3DNULL;
+=20
+   delete CORBA::_tc_float;
+   CORBA::_tc_float=3DNULL;
+  =20
+   delete CORBA::_tc_ulong;
+   CORBA::_tc_ulong=3DNULL;
+=20
+   delete CORBA::_tc_ushort;
+   CORBA::_tc_ushort=3DNULL;
+  =20
+   delete CORBA::_tc_long;
+   CORBA::_tc_long=3DNULL;
+  =20
+   delete CORBA::_tc_short;
+   CORBA::_tc_short=3DNULL;
+=20
+   delete CORBA::_tc_void;
+   CORBA::_tc_void=3DNULL;
+  =20
+   delete CORBA::_tc_null;
+   CORBA::_tc_null=3DNULL;
+  =20
+  =20
+   // remove mutexes
+   delete pd_refcount_lock;
+   pd_refcount_lock=3DNULL;
+  =20
+   delete pd_cached_paramlist_lock;
+   pd_cached_paramlist_lock=3DNULL;
+=20
+   delete aliasExpandedTc_lock;
+   aliasExpandedTc_lock=3DNULL;
+=20
+   // end of destruction
+   is_initialised =3D 0;
+ }
+=20
+=20
+=20
  // We need a singleton here as a final check, so that if no
  // stub code calls into check_static_data_is_initialised()
  // it will still be called before main().
 =20
  class TypeCodeInitialiser {
    // public just to stop brain-dead compilers complaining
  public:
    TypeCodeInitialiser() { check_static_data_is_initialised(); }
+=20
+   // when the object gets cleaned up, remove all registered interface =
pointers and exceptions
+   // then clean up the other static data
+   ~TypeCodeInitialiser() { m_trackTypeCode_ptr.delete_all(); =
remove_static_data(); }
+=20
+   // register a TypeCode_ptr for later cleanup
+   void attach(const CORBA::TypeCode_ptr& rhs)
+   {
+     m_trackTypeCode_ptr.attach(rhs);
+   }
+=20
    static TypeCodeInitialiser typecode_initialiser;
+=20
+ private:
+   TrackTypeCode_ptr m_trackTypeCode_ptr;
  };
+=20
  TypeCodeInitialiser TypeCodeInitialiser::typecode_initialiser;
+=20
+=20
+ static void track_typecode_ptr(const CORBA::TypeCode_ptr& rhs)
+ {
+   TypeCodeInitialiser::typecode_initialiser.attach(rhs);
+ }
+=20

------_=_NextPart_000_01C01F0E.4E0D2BC0--