Is it a bug in dotnet.framework? (about GC collection in 1.1 and 2

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I tried a small program, found that some local objects can't be automatically
collected by GC. I tried both in 1.1 and 2.0, get the same result.
Below the program, just try it, you will found that the last 3 objects
didn't been released. Does anyone have some idear on it?


namespace TestMem
{
class Root
{
public Int32 m_ID;
public Root()
{
m_ID = this.GetHashCode();
}
~Root()
{
System.Threading.Monitor.Enter(ObjectMgr.m_list);
ObjectMgr.UnRegister(this);
System.Threading.Monitor.Exit(ObjectMgr.m_list);
}

}
class A : Root
{
}
class B : Root
{
}
class C : Root
{
}
class ObjectMgr
{
static int m_nRegisteredCnt = 0;
static int m_nUnRegCnt = 0;
static public System.Collections.ArrayList m_list = new
System.Collections.ArrayList();
static public void Register(Root obj)
{
System.Threading.Monitor.Enter(m_list);
m_nRegisteredCnt++;
m_list.Add(obj.m_ID);
System.Threading.Monitor.Exit(m_list);
}
static public void UnRegister(Root obj)
{
System.Threading.Monitor.Enter(m_list);
m_nUnRegCnt++;
m_list.Remove(obj.m_ID);
System.Threading.Monitor.Exit(m_list);
}
static public int GetCnt()
{
System.Threading.Monitor.Enter(m_list);
int nCnt = m_list.Count;
System.Threading.Monitor.Exit(m_list);
return nCnt;
}
static public void PrintUnreleasedObjects()
{
System.Threading.Monitor.Enter(m_list);
Console.WriteLine("Registered = {0}, Unregistered={1}",
m_nRegisteredCnt, m_nUnRegCnt);
int nTmp = 0;
foreach (int objID in m_list)
{
nTmp++;
Console.WriteLine("Objects in list, ID = {0}", objID);
if (nTmp >= 10)
break;
}
System.Threading.Monitor.Exit(m_list);
}
}
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 10000; i++)
{
A a;
B b;
C c;
a = new A();
b = new B();
c = new C();
a.m_ID = 3 * i;
b.m_ID = 3 * i+1;
c.m_ID = 3 * i+2;
ObjectMgr.Register(a);
ObjectMgr.Register(b);
ObjectMgr.Register(c);
if (i % 100 == 0)
{
Console.WriteLine("i={0}",i);
}
}//
while (ObjectMgr.GetCnt() > 0)
{
Console.WriteLine("There are {0} objects in list",
ObjectMgr.GetCnt());
ObjectMgr.PrintUnreleasedObjects();
System.Threading.Thread.Sleep(5000);
GC.Collect();
}
}
}
}
 
Why would you expect any of the objects to be released?

They all have a root reference by being inserted in a *static* ArrayList. The GC.Collect() will discover that they are still reachable via the ObhectMgr.m_list. Also, in your finalizer there is no point in trying to unregister, as by the time you get there, the GC has already realized you have no root references.

Regards

Richard Blewett - DevelopMentor
http://staff.develop.com/richardb/weblog

I tried a small program, found that some local objects can't be automatically
collected by GC. I tried both in 1.1 and 2.0, get the same result.
Below the program, just try it, you will found that the last 3 objects
didn't been released. Does anyone have some idear on it?
 
In fact, the static ArrayList doesn't hold any object reference at all, it
only put the m_Id of the object into the ArrayList. So all the object should
be release by collector.
 
Yingkun Hu said:
I tried a small program, found that some local objects can't be automatically
collected by GC. I tried both in 1.1 and 2.0, get the same result.
Below the program, just try it, you will found that the last 3 objects
didn't been released. Does anyone have some idear on it?

Does that mean the program doesn't terminate for you? It does for me.

If you're running it in the debugger, that would explain things - local
variables aren't eligible for garbage collection until the method
terminates when running in the debugger,

A couple of points on the code, by the way:

1) Finalizers are horrible - get rid of them wherever possible, and
implement IDisposable wherever you *have* to have them.

2) Use lock() rather than calling Monitor.Enter/Exit explicitly.
 
Sriram Krishnan said:
Curious - why do you say this?

1) It's easier to read
2) You end up with the required try/finally (which the OP's code misses
out) automatically.
 
Back
Top