Użytkownik Jeroen Frijters <[EMAIL PROTECTED]> napisał:
>Shawn A. Van Ness wrote:
>> Ok, so I grant that GC.KeepAlive(this) does have some effect.

Well, I cannot produce the problem with a C#/Managed C++ program. The C# part 
looks as follows (it is a bit messy, as I have modified a more complex program):

    private class Q
    {
      private OctetStr os = new OctetStr("qwertyuiop");
      public Q()
      {
        Console.Error.WriteLine("Q created!");
      }
      public void Th()
      {
        OctetStr temp = os;
        os = null;
        Console.Error.WriteLine(temp.ToHexString());
      }
    }
    public static void Main(string[] args)
    {
      System.Threading.Thread t = new System.Threading.Thread(new 
System.Threading.ThreadStart(new Q().Th));
      t.Start();
      t = null;
      Q q = new Q();
      q = null;

      System.Threading.Thread.Sleep(1000);
      Console.Error.WriteLine("collecting!");
      GC.Collect();
      GC.WaitForPendingFinalizers();
      GC.Collect();
      Console.Error.WriteLine("collected!");

      System.Threading.Thread.Sleep(5000);

      if (args.Length < 2)
      {
         Console.Error.WriteLine("In main!");
         Environment.Exit(1);
      }

OctetStr is a simple managed wrapper over an unmanaged C++ object (compiled 
separately to a DLL), with a finalizer printing "gone!!"; ToHexString() creates 
copy of its unmanaged state, then calls appropriate (unmanaged) method that  
sleeps for 10 seconds, then produces a result. The output is:

Q created!
Q created!
Sleeping...!
collecting!
gone!!
collected!
Sleeping end!
  71 77 65 72 74 79 75 69 6F 70

In main!
gone!!
CRT terminated!  (which means that DLL has been terminated)

when I comment out the second Q object:

//      Q q = new Q();
//      q = null;

I will get

Q created!
Sleeping...!
collecting!
collected!
Sleeping end!
  71 77 65 72 74 79 75 69 6F 70

In main!
gone!!
CRT terminated!

It looks like something keeps OctetStr from being GC-ed and finalized during a 
native method call (in both cases, the program was compiled in a Debug mode, 
which collects quite reliably). What is interesting in the managed 
ToHexString() is that it creates a local (on stack) copy of the wrapped 
unmanaged object, then uses the copy to produce the result. 'this' in the 
managed OctetStr is then no more used, yet the object is prevented from being 
GC-ed. If you are curious, it looks as follows:

__gc class OctetStr
{
public:
  ~OctetStr() { Console::Error->WriteLine("gone!!"); }
  String* ToHexString() {
    return SafePrintableHexT<::OctetStr>(
      dynamic_cast<const ::OctetStr&>(WrappedRef()));
  }
// etc.
};

where

template<typename UT>
String* SafePrintableHexT(const UT& ut) {

  UT copy(ut);
  String* s;
  if (ut.valid() && (s = (String*) ut.get_printable_hex()) != 0) {
    return s;
  }
  else {
    throw new UnmanagedOutOfMemoryException();
  }
}

(::OctetStr is the wrapped unmanaged type and get_printable_hex() is the 
long-taking function).

Of course, this is managed C++, which may behave in a different way (it is 
assumed to do lots of unmanaged work). Writing proxies with GC::KeepAlive(this) 
even for a single line code would look insane, I think, for managed C++.

Marek

===================================
This list is hosted by DevelopMentorŽ  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to