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