Special case lifetime analysis - c#

Suppose I have
void foo () {
Bar bar = new Bar(); // bar is never referred to after this line
// (1)
doSomethingWithoutBar();
}
At (1), is the object bar is pointing to eligible for garbage collection? Or does bar have to fall out of scope as well? Does it make a difference if GC.Collect is called by doSomethingWithoutBar?
This is relevant to know if Bar has a (C#) destructor or something funky like that.

Objects can become eligible for garbage collection as soon as it's certain that they will no longer be used. It's entirely possible that bar will be garbage collected before the variable goes out of scope.
Proof:
using System;
class Bar
{
~Bar() { Console.WriteLine("Finalized!"); }
}
class Program
{
static void Main(string[] args)
{
Bar bar = new Bar();
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
}
Run in Release Mode (because it doesn't get collected in Debug Mode).
Output:
Finalized!
Press any key to exit...
It also works on ideone which uses Mono. The output is the same.

From a quick reading of the spec, it looks like it's implementation specific. It's allowed to garbage collect it, but not required to.
I get this from a note in section 10.9 "Automatic Memory Management" of the ECMA Spec:
[Note: Implementations might choose to analyze code to determine
which references to an object can be used in the future. For
instance, if a local variable that is in scope is the only existing
reference to an object, but that local variable is never referred to
in any possible continuation of execution from the current execution
point in the procedure, an implementation might (but is not required
to) treat the object as no longer in use. end note]
Emphasis mine.

Without defining what version of the CLR you're referring to, it's impossibledifficult to be definitive about the behaviour that you'll see here.
A hypothetical CLR could, in this example, assuming that the following is true:
The constructor for Bar does nothing
There are no fields that are initialised (i.e. there are no potential side-effects to the objects construction)
Entirely disregard the line Bar bar = new Bar(); and optimise it away as it "does nothing".
As far as my memory serves, in current versions of the CLR bar is eligible for garbage collection the moment after you've constructed it.

Marc answered the question, but here is the solution:
void foo () {
Bar bar = new Bar(); // bar is never referred to after this line
// (1)
doSomethingWithoutBar();
GC.KeepAlive(bar); // At the point where you no longer need it
}

This can definitely occur. For instance, here is a demonstration that an instance can be finalized while you are still executing its constructor:
class Program
{
private static int _lifeState;
private static bool _end;
private sealed class Schrodinger
{
private int _x;
public Schrodinger()
{
//Here I'm using 'this'
_x = 1;
//But now I no longer reference 'this'
_lifeState = 1;
//Keep busy to provide an opportunity for GC to collect me
for (int i=0;i<10000; i++)
{
var garbage = new char[20000];
}
//Did I die before I finished being constructed?
if (Interlocked.CompareExchange(ref _lifeState, 0, 1) == 2)
{
Console.WriteLine("Am I dead or alive?");
_end = true;
}
}
~Schrodinger()
{
_lifeState = 2;
}
}
static void Main(string[] args)
{
//Keep the GC churning away at finalization to demonstrate the case
Task.Factory.StartNew(() =>
{
while (!_end)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
});
//Keep constructing cats until we find the desired case
int catCount = 0;
while (!_end)
{
catCount++;
var cat = new Schrodinger();
while (_lifeState != 2)
{
Thread.Yield();
}
}
Console.WriteLine("{0} cats died in the making of this boundary case", catCount);
Console.ReadKey();
}
}
In order for this to work, you need to emit a Release build and run it outside Visual Studio (as otherwise the debugger inserts code that prevents the effect.) I've tested this with VS 2010 targetting .NET 4.0 x64.
You can tweak the iterations on the 'keep busy' loop to impact the probability of the Cat winding up finalized before its complete construction.

Related

In c# how to know if a weak referenced object is going to be garbage collected?

Suppose I have such code:
class Test
{
WeakReference m_ref;
public Test()
{
Test1();
Test2();
}
void Test1()
{
m_ref = new WeakReference(new object());
}
void Test2()
{
// If I do the GC then the m_ref.Target is null
// GC.Collect();
Debug.Log(m_ref.Target);
}
}
void TestFunc()
{
new Test();
}
In this example I created a new object instance and set it to a WeakReference instance in Test1. If I understand correctly after exit the Test1 there would be nothing referenced to the object instance so this instance would be GC soon.
However, in the Test2 if GC is not performed I can still access the object instance via m_ref.Target.
Is there any way I could know that the m_ref.Target is invalid without manually perform the GC?
Nope, you can't. By design, WeakReference is tightly coupled to the garbage collector. Even the documentation mentions it:
Gets an indication whether the object referenced by the current WeakReference object has been garbage collected.
As far as I know, there's no way in C# to know whether there's still alive references to a given object, except maybe manually browsing the whole reference tree (and pretty much reimplementing the GC yourself).
Is there any way I could know that the m_ref.Target is invalid without manually perform the GC?
It is not invalid until the GC collects the object. The point of garbage collection is that you don't know and you don't have to take care of when the object is going to be discarded.
In your example, yes, you are right that after m_ref = new WeakReference(new object()); is executed, the instance will be collected 'soon'. However, 'soon' is not defined specifically whatsoever, so you cannot presume this will happen before Test2 is invoked and Debug.Log(m_ref.Target); executed.
If I understand correctly after exit the Test1 there would be nothing referenced to the object instance ...
You are wrong. Technically you don't have any reference of created object, it may be gc'ed on the next line.
Consider this simple example:
class Program
{
static WeakReference _ref;
static void Main(string[] args)
{
Test();
GC.Collect();
Console.WriteLine(_ref.IsAlive); // false
}
static void Test()
{
var obj = new object();
_ref = new WeakReference(obj);
GC.Collect();
Console.WriteLine(_ref.IsAlive); // true
}
}
In Test() we have strong reference to an object, it indeed persist until end of method.
You can do something like this to be sure
object obj = _ref.Target;
if (obj != null)
{
... safe to do something with obj
}
You can not tell if a WeakReference is valid. But you can tell if it is invalid.
I know that is strange. If I have code that does an if statement and could ask "is it valid" then it could be invalid on the next line of code, so it is useless.
The TryGetTarget call on WeakReference gets a reference to the object, or fails and returns false.
Once it has a reference, the reference prevents the object from being garbage collected, so it will stay valid at least as long as you have the reference.
In some code one might be keeping a List<WeakReference<MyNiftyClass>>
One great way to keep track of that list and keep it clean of unreferenced (elsewhere) references is to have some for loop scan the list with TryGetTarget and if it fails remove the stale reference from the list.
But a removal like that wrecks the iterator so you want to use RemoveAll with a predicate.
I have a class called CognateBase and a static global list called AllCognateBases.
The CognateBase has a Tick() function I call every time tick of the program.
The Tick loop is a good place to reap stale references. So I have...
public static void TickAll()
{
// This will loop through all CognateBase objects and call their Tick, or if deleted from memory, remove the CognateBase.
AllCognateBases.RemoveAll(_TickIfAble);
}
And then the _TickIfAble is
private static bool _TickIfAble(WeakReference<CognateBase> r)
{
CognateBase cb;
if (r.TryGetTarget(out cb))
{
cb.Tick();
return false;
}
else
{
return true;
}
}
Thus the CognateBase instances that are valid get ticked, and the ones that are not valid any more get removed. And because it is in RemoveAll there is no iterator to get messed up.
Anywhere else in the code where I have a reference to a CognateBase and set it to null, the CognateBase will eventually get deleted and removed from the list.
And this test works. All those GC calls are to force Garbage Collection to happen NOW not some time later when C# feels like it.
public static void UnitTest()
{
Debug.Assert(AllCognateBases.Count == 0);
CognateBase b1 = new CognateBase();
Debug.Assert(AllCognateBases.Count == 1);
CognateBase b2 = new CognateBase();
Debug.Assert(AllCognateBases.Count == 2);
GC.Collect();
Debug.Assert(AllCognateBases.Count == 2);
b1 = null;
GC.Collect();
GC.WaitForFullGCComplete();
GC.WaitForPendingFinalizers();
TickAll();
GC.Collect();
GC.WaitForFullGCComplete();
GC.WaitForPendingFinalizers();
Debug.Assert(AllCognateBases.Count == 1);
b2 = null;
GC.Collect();
GC.WaitForFullGCComplete();
GC.WaitForPendingFinalizers();
TickAll();
GC.Collect();
GC.WaitForFullGCComplete();
GC.WaitForPendingFinalizers();
Debug.Assert(AllCognateBases.Count == 0);
}
And the creator...
public CognateBase()
{
AllCognateBases.Add(new WeakReference<CognateBase>(this));
}
WARNING - WHen a reference is set to null like the above b1 = null; the objects may not get garbage collected for a looooooong time. All that time it is still valid and will get it's Tick called!

Isn't it illegal C# code to jump into a label inside a loop from outside the loop?

At about 09:19 in this video on Channel 9 where Jeffrey Richter demonstrates his AsyncEnumerator to Charlie Calvert, he shows a piece of code where the flow-of-control jumps to a label inside a while loop obeying a goto instruction that is outside the loop. That blew me away. I was in disbelief for a moment.
So, I tried something similar, and as I expected, C# does not let me do that because the label is not in the block scope of the goto statement from where I want to jump.
using System;
namespace JumpToInsideALoopWithGoToTest
{
class Program
{
static int i = 0;
static int someRandomNumber = 0;
static void Main(string[] args)
{
Console.WriteLine("\nPress any key to continue...");
Console.ReadKey();
}
static bool GoToInsideLoopTest(int howMany)
{
if (i == 0)
{
i = 1; return true;
}
if (i == 1)
{
while (someRandomNumber < howMany)
{
i = 2;
return true;
Increment: i++;
}
}
if (i == 2)
{
goto Increment;
}
return false;
}
}
}
What then? I don't even know what my question here is. Like, what was that I saw then?
I am suspecting the code he showed was pseudo code? Or may be such a thing is possible in IL? At any rate, what was that?
Maybe he was demonstrating the state machine that the C# compiler generates for async and iterator methods. The compiler does not need to adhere to C# syntax requirements. All it needs to do is make the CLR happy.
At the CLR level all local variables are declared at the top of the function so to speak. They are available everywhere. There are not declaration issues and no issues with uninitialized variables.
The CLR imposes its own requirements which mostly are about the execution stack being properly formed. This is not an issue when jumping to locations where the stack is empty such as between statements. Since await can appear within expressions there is a rewrite that rewires everything so that the state machine jumps are to locations with empty stack.
For the C# compiler it's not a problem to jump to pretty much any place.

Dictionary with a class as the value.

I have a small class that I use as the value in a dictionary. When I delete the dictionary will it also destroy the class instance?
class Program
{
class Test
{
public string A_String;
public string B_String;
}
static Dictionary<int, Test> _dict = new Dictionary<int, Test>();
static void Main(string[] args)
{
for(int X = 0; X <=5; X++)
{
Test _test = new Test();
_test.A_String = "A" + X.ToString();
_test.B_String = "B" + X.ToString();
_dict.Add(X, _test);
}
_dict.Remove(2);
}
}
No. You can access test as long as it is in scope.
But since each instance of test goes out of scope after each cycle of the for loop, you can't get to it if you remove it from the dictionary.
static void Main(string[] args)
{
for(int X = 0; X <=5; X++)
{
Test _test = new Test();
_test.A_String = "A" + X.ToString();
_test.B_String = "B" + X.ToString();
_dict.Add(X, _test);
// each _test goes out of scope here
}
_dict.Remove(2);
// Removed from dictionary, have no way to access it now.
I have assumed your question is about whether you can access it. If it is about "deletion" in the unmanaged memory sense, forget it, there is no deterministic deletion, that's what garbage collectors are for.
When I delete the dictionary will it also destroy the class instance?
The garbage collector, which is responsible to dispose the object from the memory, will CONSIDER the object a candidate for collection when all references to that object are gone. In your example when you remove the second element from the dictionary _test is not referenced anymore, as you defined and instantiated it within the for loop scope. Then it should become a CANDIDATE for collection.
From the MSDN on when the garbage collector executes:
Garbage collection occurs when one of the following conditions is
true:
The system has low physical memory.
The memory that is used by
allocated objects on the managed heap surpasses an acceptable
threshold. This threshold is continuously adjusted as the process
runs.
The GC.Collect method is called. In almost all cases, you do not
have to call this method, because the garbage collector runs
continuously. This method is primarily used for unique situations and
testing.
when control flow exits from Main or any other method where you define and use the dictionary, .Net Garbage collector knows that such dictionary and all items in the dictionary are no longer used. And when GC runs next time it will potentially clean them up. However, you need not worry about whether they are cleaned up or not. As long as they are instance variables, they will surely be cleaned up once they go out of scope.

C# Delete Instance of Class?

I am sort of new to C# and I have a quick question about instances of classes.
I was told that using only "null"on an instance of a class isn't enough to delete an entire instance and all it's resources, such as pointers, etc. So I have:
ClassHere myClass = new ClassHere() and myClass = null
I really must be thinking about this too hard... I'll give an example as to figure out how exactly the GC works.
Let's say we have 3 instances: x1, x2, x3. Each instance would be mapped to a variable: ClassHere myClass = new ClassHere() except you'd have x1, x2 and x3 instead of myClass.
Then say instances x2 and x3 make some sort of reference to x1. Let's say that x1 does nothing after being referenced by x2 and x3. The GC would only pick up x1 after x2's, and x3's references of x1 would be removed, correct?
If it picks it up even with those references. How would the GC know whether or not I actually need instance x1 which is referenced by x2 and x3 instead of deleting it?
Or am I missing something here?
Well, the only way to destroy a class is to remove it from your source tree :D You can, though destroy instances of a class.
Unlike C++, C# doesn't have deterministic destructors. An object instance becomes eligible for garbage collection when the object instance becomes unreachable. That can happen by virtue of
all references to it being released (e.g., variable going out of scope), or
all references to it being themselves unreachable (e.g., the object instance is references in a collection, and the collection is itself unreachable.
When and if an object instance is garbage-collected depends on memory/resource pressure within the app domain (process). When the app domain ends, though, everything is garbage collected.
Usually you want to make things that matter implement IDisposable, so non-managed resources held can be deterministically released via using blocks and the like.
This is a simplistic answer, but the gist of it is: don't sweat it.
Any of your managed resources you don't need to worry about "deleting". The Garbage Collector will take care of this for you. You only need to worry about cleanup in the case where you are using unmanaged resources(Which I'm assuming you aren't as you don't mention it).
You do not need to null out variables for the GC to collect it.
Here's a link I found on a related stackoverflow question that might help:
http://blogs.msdn.com/b/oldnewthing/archive/2010/08/10/10048149.aspx
If the code is running on a server GC isn't going to deallocate the object- unless you restart the server every half hour- seems like a legitimate question to me... I had a similar problem- detecting when a user shuts the browser as opposed to manually logging off the website- my solution was to create an instance for user with a timer and a flag that is set to true via ajax and reset to false by server side timer. But there was a potential for memory leaks- since there was no guarantee instance of the user was being deallocated when they would be automatically logged off.
So I create a class user outside webservice like this and instantiated a list of type user:
class WebService{
public static List<user> UserLoglist = new List<user>();//list of logged in users
[WebMethod(Description = "Per session Hit Counter", EnableSession = true)]
public void ClnUpdateFlag(string un)//gets called via ajax
{//Updates the flags i
//update users status
WebService.UserLoglist.Find(y => y.username == un).isLoggedin = true;
}
}
public class user
{
public string username;
public System.Timers.Timer timScheduledTask = new System.Timers.Timer();
public bool isLoggedin = true;
public user(string puser)
{
username = puser;
setimer(); //set server side timer
}
void Timer1_Tick(object sender, EventArgs e)
{
...
if (isLoggedin)// window is still open
isLoggedin = false;
else// user closed the window
{
...
WebService.UserLoglist.RemoveAll(x => x.username == username);// instance is deleted here
...
}
}
}
void setimer()
{
timScheduledTask.Interval = 3000;
timScheduledTask.Enabled = true;
timScheduledTask.Start();
timScheduledTask.Elapsed +=
new System.Timers.ElapsedEventHandler(Timer1_Tick);
}
}
}
class login{
...
public void Logon_Click(object sender, EventArgs e)
{
if (Membership.ValidateUser(UserEmail.Text, UserPass.Text)){
...
WebService.UserLoglist.Add(new user(UserEmail.Text));// instance of the user is instantiated here
}
...
}
}

GC contains lots of pinned objects after a while

I have a strange phenomenon while continuously instantiating a com-wrapper and then letting the GC collect it (not forced).
I'm testing this on .net cf on WinCE x86. Monitoring the performance with .net Compact framework remote monitor. Native memory is tracked with Windows CE Remote performance monitor from the platform builder toolkit.
During the first 1000 created instances every counter in perfmon seems ok:
GC heap goes up and down but the average remains the same
Pinned objects is 0
native memory keeps the same average
...
However, after those 1000 (approximately) the Pinned object counter goes up and never goes down in count ever again. The memory usage stays the same however.
I don't know what conclusion to pull from this information... Is this a bug in the counters, is this a bug in my software?
[EDIT]
I do notice that the Pinned objects counter starts to go up as soon the total bytes in use after GC stabilises as does the Objects not moved by compactor counter.
The graphic of the counters http://files.stormenet.be/gc_pinnedobj.jpg
[/EDIT]
Here's the involved code:
private void pButton6_Click(object sender, EventArgs e) {
if (_running) {
_running = false;
return;
}
_loopcount = 0;
_running = true;
Thread d = new Thread(new ThreadStart(LoopRun));
d.Start();
}
private void LoopRun() {
while (_running) {
CreateInstances();
_loopcount++;
RefreshLabel();
}
}
void CreateInstances() {
List<Ppb.Drawing.Image> list = new List<Ppb.Drawing.Image>();
for (int i = 0; i < 10; i++) {
Ppb.Drawing.Image g = resourcesObj.someBitmap;
list.Add(g);
}
}
The Image object contains an AlphaImage:
public sealed class AlphaImage : IDisposable {
IImage _image;
Size _size;
IntPtr _bufferPtr;
public static AlphaImage CreateFromBuffer(byte[] buffer, long size) {
AlphaImage instance = new AlphaImage();
IImage img;
instance._bufferPtr = Marshal.AllocHGlobal((int)size);
Marshal.Copy(buffer, 0, instance._bufferPtr, (int)size);
GetIImagingFactory().CreateImageFromBuffer(instance._bufferPtr, (uint)size, BufferDisposalFlag.BufferDisposalFlagGlobalFree, out img);
instance.SetImage(img);
return instance;
}
void SetImage(IImage image) {
_image = image;
ImageInfo imgInfo;
_image.GetImageInfo(out imgInfo);
_size = new Size((int)imgInfo.Width, (int)imgInfo.Height);
}
~AlphaImage() {
Dispose();
}
#region IDisposable Members
public void Dispose() {
Marshal.FinalReleaseComObject(_image);
}
}
Well, there's a bug in your code in that you're creating a lot of IDisposable instances and never calling Dispose on them. I'd hope that the finalizers would eventually kick in, but they shouldn't really be necessary. In your production code, do you dispose of everything appropriately - and if not, is there some reason why you can't?
If you put some logging in the AlphaImage finalizer (detecting AppDomain unloading and application shutdown and not logging in those cases!) does it show the finalizer being called?
EDIT: One potential problem which probably isn't biting you, but may be worth fixing anyway - if the call to CreateImageFromBuffer fails for whatever reason, you still own the memory created by AllocHGlobal, and that will currently be leaked. I suspect that's not the problem or it would be blowing up more spectacularly, but it's worth thinking about.
I doubt it's a bug in RPM. What we don't have here is any insight into the Ppb.Drawing stuff. The place I see for a potential problem is the GetIImagingFactory call. What does it do? It's probably just a singleton getter, but it's something I'd chase.
I also see an AllochHGlobal, but nowhere do I see that allocation getting freed. For now that's where I'd focus.

Categories

Resources