I have a main method that has this code:
List<MyType> myList = openDialog();
The call to the openDialog that open a dialog that returns a list with selected items, the dialog is to select items.
private List<MyType> openDialog()
{
MyView myView = new MyView();
MyViewModel myViewModel = new MyViewModel();
myView.DataContext = myViewModel;
myView.ShowDialog();
return myViewModel.Result;
}
myViewModel.Result is a collection that has the selectedItems of the a datagrid in the view.
My question is, how I am returning the Result property of the ViewModel, I am not sure if myViewModel will be recollected by the garbage collector or not, because it still has a reference to it.
To avoid this I am doing this:
private List<MyType> openDialog()
{
MyView myView = new MyView();
MyViewModel myViewModel = new MyViewModel();
myView.DataContext = myViewModel;
myView.ShowDialog();
return new List<MyType>(myViewModel.Result);
}
In the return, I am creating a new list to avoid to reference to the Result property and ensure that the myViewModel object is recollected, but I would like to know if there is a way to avoid to create a new list.
You haven't posted the implementation of MyViewModel but the the List<MyType> returned from the view model won't prevent the view model from being garbage collected. You can confirm this yourself using a WeakReference:
private void Test(object sender, RoutedEventArgs e)
{
Window myView = new Window();
MyViewModel myViewModel = new MyViewModel();
myView.DataContext = myViewModel;
myView.ShowDialog();
List<MyType> result = myViewModel.Result;
WeakReference viewModelWeakReference = new WeakReference(myViewModel);
myView.DataContext = null;
myViewModel = null;
GC.Collect();
GC.WaitForPendingFinalizers();
bool isViewModelAlive = viewModelWeakReference.IsAlive; //=false
}
...
public class MyViewModel
{
public List<MyType> Result { get; } = new List<MyType>() { new MyType(), new MyType() };
}
isViewModelAlive is false and result.Count is 2 when running the above sample code, i.e. the view model has been collected but the List<MyType> remains in memory.
Note that WeakReference.IsAlive will return true when you hold a strong reference to the method that performs the GC test:
List<MyType> _result;
private void Button_Click(object sender, RoutedEventArgs e)
{
_result = openDialog();
}
private List<MyType> openDialog()
{
Window myView = new Window();
MyViewModel myViewModel = new MyViewModel();
myView.DataContext = myViewModel;
myView.ShowDialog();
List<MyType> result = myViewModel.Result;
WeakReference viewModelWeakReference = new WeakReference(myViewModel);
myView.DataContext = null;
myViewModel = null;
GC.Collect();
GC.WaitForPendingFinalizers();
bool isViewModelAlive = viewModelWeakReference.IsAlive;
return result;
}
But myViewModel will still be eligible for garbage collection once the method has returned as it has no GC roots.
So there is no need to create another List<MyType> here.
This question is a little confused. However lets test it out.
Given
public class MyGCCollectClass
{
public List<Version> Garbage { get; set; }
public List<int> MyInnocentList { get; set; }
public List<int> Main()
{
Garbage = new List<Version>();
for (var i = 0; i < 10000000; i++)
{
Garbage.Add(new Version());
}
MyInnocentList = new List<int>();
return MyInnocentList;
}
}
We can look at whats being collected and not
// Lets start from a collect
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Memory used before collection: {0:N0}", GC.GetTotalMemory(false));
// create a class/viewmodel
var gcCollectClass = new MyGCCollectClass();
// create a world of garbage
// return back a list that is part of the class
var list = gcCollectClass.Main();
// lets see whats GC has
Console.WriteLine("Memory used: {0:N0}", GC.GetTotalMemory(true));
// make sure our garbage is still alive
Console.WriteLine(gcCollectClass.Garbage.Count);
// Kill the original class
gcCollectClass = null;
// Force a collection
GC.Collect();
GC.WaitForPendingFinalizers();
// double check the list is still alive
Console.WriteLine(list.Count);
// Lets make sure we havent caused a memory leak
Console.WriteLine("Memory used after full collection: {0:N0}",
GC.GetTotalMemory(true));
Output
Memory used before collection: 30,088
Memory used: 307,138,940
10000000
1
Memory used after full collection: 29,968
The fact is, just because you are returning a list from your class and its part of the class doesn't mean returning it will stop your viewmodal from being cleaned up. It "will" get collected in this situation and there are no memory leaks
Further reading
Why doesn't C# support the return of references?
Memory in .NET - what goes where
The memory slot for a variable is stored on either the stack or the
heap. It depends on the context in which it is declared:
Each local variable (ie one declared in a method) is stored on the stack. That includes reference type variables - the variable itself is
on the stack, but remember that the value of a reference type variable
is only a reference (or null), not the object itself. Method
parameters count as local variables too, but if they are declared with
the ref modifier, they don't get their own slot, but share a slot with
the variable used in the calling code. See my article on parameter
passing for more details.
Instance variables for a reference type are always on the heap. That's where the object itself "lives".
Instance variables for a value type are stored in the same context as the variable that declares the value type. The memory slot for the
instance effectively contains the slots for each field within the
instance. That means (given the previous two points) that a struct
variable declared within a method will always be on the stack, whereas
a struct variable which is an instance field of a class will be on the
heap.
Every static variable is stored on the heap, regardless of whether it's declared within a reference type or a value type. There is only
one slot in total no matter how many instances are created. (There
don't need to be any instances created for that one slot to exist
though.) The details of exactly which heap the variables live on are
complicated, but explained in detail in an MSDN article on the
subject.
https://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/
Whether the object referenced by myViewModel variable can be collected depends on whether any other reachable object references it. In this case, assuming no one else has a reference to it, it depends on whether the object returned by the myViewModel.Result property has any reference (e.g. field, property, delegate) to it. If it doesn't, the copying of the collection isn't necessary. If it does, the copy seem to be an acceptable solution.
Unless the view model uses some limited resources (database connection, file handles, network connections and so on, in which case it should use IDisposable pattern), there's no reason to be overly anxious about its garbage collection.
However, to satisfy one's curiosity, you may test whether the object is GCed using the answer here.
Related
Consider the following pseudo code:
public class SomeComponent
{
private List<DisposableFoo> _foos = new List<DisposableFoo>();
public void Start()
{
for (int i = 0; i < 5; i++)
{
var foo = new DisposableFoo();
var bar = new DisposableBar(); <-- EXPLICIT DISPOSE NEEDED?
foo.SomeFunc = x => bar.DoSomethingWithX(x);
_foos.Add(foo);
}
}
public void Stop()
{
_foos.ForEach(f => f.Dispose());
}
}
Does the infrastructure take care of Disposing any captured IDisposable variables as part of it's tear down?
Clarification:
I am not asking about best practices around managing disposable objects. My question is more about what does the infrastructure do in this instance. My understanding is that for capturing variables, behind the scenes the infrastructure creates a type that contains a field of type DisposableBar and it receives a reference to the object in the 'bar' variable. Once the infrastructure has captured that variable it seems like a 'gray area' to me about whose responsibility it is at that point to determine when the variable is no longer needed and can be disposed.
The short answer is yes most definitely. You need to call dispose on any object that is disposable. This is used to clean up unmanaged resources and dependencies.
Also NOTE: The garbage collector does not call Dispose on or look for IDisposable types.
If it is disposable within the method then it is ideal to use a using statement like so.
public void Start()
{
for (int i = 0; i < 5; i++)
{
using (var foo = new DisposableFoo())
using (var bar = new DisposableBar())
{
foo.SomeFunc = x => bar.DoSomethingWithX(x);
_foos.Add(foo);
}
}
}
If the variable is class level then your class should also implement IDisposable and dispose of the disposable objects it uses within it as well.
Here is a good link where I give more detail about disposing objects.
Another thing to keep in mind is that sometimes (in languages like C#) we can have circular dependencies (which is bad practice.) However; it happens a lot. If your object is garbage collected and there is a circular dependency it hangs around until the other object is also garbage collected and it causes the process to be ugly. It's all behind the scenes and usually isn't a big deal for most apps but being aware of this is important. Although you should not have circular dependencies you can implement IDisposable to clean up dependencies before going to the garbage collector, making this process cleaner. (Just remember having them is bad to start with... That said, Entity Framework is built on circular dependencies so go figure.)
Another NOTE: It is not uncommon to see the Dispose method added also to the destructor of an object; especially if the object is lower level, singleton, or static, to insure the disposable types are taken care of during garbage collection. This would look something like:
public class SomeClass : IDisposable
{
//pretend we implement a singleton pattern here
//pretend we implement IDisposable here
~SomeClass()
{
Dispose();
}
}
UPDATE:
To update the answer based on your clarification I believe you're asking what happens to the variable you retrieve from a disposable object, after that disposable object is disposed. This is tricky behavior and should be thought out well when developing a disposable type. Here's some code that shows the results of similar situation that might help you understand.
Also. whose responsible for this should be decided when developing the type but in most cases any information you give to the client should be left good for the client even after you're disposed. In other words, it would be best practice to NOT remove or dispose or manipulate any information you allow the user of your type to retrieve when you are disposing.
using System;
using System.Collections.Generic;
namespace Disposable_Variables_Reference
{
class Program
{
static void Main(string[] args)
{
List<string> DCNames = null;
string DCName = string.Empty;
int DCValue;
using (var disposableClass = new DisposableClass())
{
DCNames = disposableClass.Names;
DCName = disposableClass.Name;
DCValue = disposableClass.Value;
foreach (var name in DCNames) Console.WriteLine(name);
Console.WriteLine(DCName);
Console.WriteLine(DCValue);
}
foreach (var name in DCNames) Console.WriteLine(name);
Console.WriteLine(DCName);
Console.WriteLine(DCValue);
Console.Read();
}
public class DisposableClass : IDisposable
{
public List<string> Names { get; set; } = new List<string>() { "Michael", "Mark", "Luke", "John" };
public string Name { get; set; } = "Gabriel";
public int Value { get; set; } = 20;
public void Dispose()
{
Names.Clear();
Name = string.Empty;
Value = 0;
}
}
}
}
Output:
Michael
Mark
Luke
John
Gabriel
20
Gabriel
20
Names is a List (reference type) and IS NOT re-written to the output.
Name is string (immutable reference type) and IS re-written to the output.
Value is int (value type) and IS re-written to the output.
However; if you reassign Names in the Dispose() method, instead of clearing it, then it WILL ALSO be re-written. Example including just the dispose method change.
public void Dispose()
{
Names = null; //notice here we re-assign Names to null.
Name = string.Empty;
Value = 0;
}
New Output:
Michael
Mark
Luke
John
Gabriel
20
Michael
Mark
Luke
John
Gabriel
20
Knowing this the proper way to expose Names would be to leave it alone in the Dispose() method or expose name like so; returning a new list, so that any referendes to it are not removed when disposing.
private List<string> names = new List<string>() { "Michael", "Mark", "Luke", "John" };
public List<string> Names
{
get { return names.ToList() ; }
set { names = value; }
}
Of course this entire answer is for logic and clarification. There is no reason to use IDisposable in the DisposableClass example I've given.
If you have used unmanaged code in DisposableBar than it needed to be disposed, else Garbage collator will take care managed resources.
Yes and no. The proper thing to do will be to dispose manually. If this code is similar to the real app you should gather the bars in a list and dispose them after you dispose the foos. Depending on how your real code is structured you might need another strategy. If the bar is unmanaged resource you should always dispose it. In most cases the unmanaged resource is wrapped in a managed resource for example StreamReader wraps an unmanaged file handle. In these cases the object will be disposed when the managed object is garbage collected assuming that the dispose pattern is implemented correctly. The problem is that the GC is not deterministic and will run when there is memory pressure. There might be a situation where GC does not run but your app is starved for file handlers but since GC only cares about memory it does not run and the unmanaged resource is not disposed.
I wanted to understand more about how the ref keyword works so I made the following experiment:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var main = new Main { Property = 1 };
var dependent = new Dependent(main);
void ChangeRef(ref Main Oldmain, Main newMain)
{
Oldmain = newMain;
}
ChangeRef(ref main, new Main { Property = 5 });
Assert.AreEqual(5,dependent.Main.Property);
}
}
public class Main
{
public int Property { get; set; }
}
public class Dependent
{
public Dependent(Main main)
{
Main = main;
}
public Main Main { get; set; }
}
As you can see I was expecting to be able to replace the object that main was referencing while keeping the reference, but the test fails and with the value still being 1. Could someone elaborate abit on why that wasnt working or point me to a place where I can read more?
Update:
Like someone answered below, but later removed.
Why doesnt it work if I pass the main object by reference to the dependent in the constructor?
Shouldnt they all have the same reference?
As others have pointed, you cannot instantly make all variables and fields in your program point to a different instance.
But if you want to reflect a change in all parts of the program, the simplest way is to wrap it in a different class (like your Dependent class). Then you can share the class with other parts of the program, and change its properties instead:
class SomeOtherObject
{
readonly Dependent _dependent;
public Dependent { get { return _dependent; }}
public SomeOtherObject(Dependent dependent)
{
_dependent = dependent;
}
public void Print()
{
Console.WriteLine(_dependent.Main.Property);
}
}
So now you can do this:
var dependent = new Dependent(new Main { Property = 1 });
var someOtherObject = new SomeOtherObject(dependent);
// this will print "1"
someOtherObject.Print();
dependent.Main = new Main { Property = 5; };
// this will print "5"
someOtherObject.Print();
In this case, obviously, simply changing dependent.Main.Property would also do the trick. So, if all parts of your program point to a single object, you can mutate it (i.e. change its internal data) and everyone will see the change, but you cannot make all parts of your program change what they are pointing to.
It's worth noting that you need to be careful when doing this in multithreaded programs; you rarely want some other thread to be able to randomly change your internal data.
That's also why it's best to try to keep your properties readonly, and your objects immutable, if possible.
After doing that
var main = new Main { Property = 1 };
You have object of type Main allocated somewhere in memory (let's name it Main1), at some memory address X, and variable main points to that object. "Points" means it literally stores address of that object Main1, so main contains X.
Then you pass reference to Main1 to the constructor of Dependent object
var dependent = new Dependent(main);
Dependent object is also allocated somewhere in memory, and one of its fields stores reference to Main1 object. So dependent.Main also stores X.
When you do
ChangeRef(ref main, new Main { Property = 5 });
You allocate new object Main5 somewhere at memory address Y. Now you change what address variable main points to. Before it stored address X (address of Main1), now it stores address Y (address of Main5). But dependent.Main still stores address X, because you didn't change it in any way, so it still points to object Main1.
Why does calling ShallowCopy below fail the Debug.Assert? I expect that the two properties are referencing different collections.
public class MyClass : DependencyObject
{
public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
"Items",
typeof(ObservableCollection<int>),
typeof(MyClass),
new PropertyMetadata(default(ObservableCollection<int>)));
public ObservableCollection<int> Items
{
get { return (ObservableCollection<int>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public MyClass ShallowCopy()
{
Items = new ObservableCollection<int>();
var copy = (MyClass)this.MemberwiseClone();
copy.Items = new ObservableCollection<int>();
Debug.Assert(!ReferenceEquals(copy.Items,Items), "WHY???");
return copy;
}
}
You cannot clone arbitrary objects. A given object must support being cloned. Calling Object.MemberwiseClone on anything is unsafe by default unless you can show it's safe.
For example, what would cloning a FileStream or a Button do in your mind? It does not make sense.
It's like when you use private reflection to mess with some object's internal state. You get undefined behavior. Really, anything can happen.
If you are curious why you are getting this exact behavior you need to decompile DependencyObject.Items.set to see why are corrupted DependencyObject might misbehave in such a way. My guess: Both the old and the new object are sharing some state due to all fields just being copied over. That's why setting Items on one object also sets it on the other. It's really the same variable underneath.
Object.MemberwiseClone is a design mistake in the .NET Framework because it is not possible to protect that method adequately. It's mere existence is unsafe by default as you found out.
If I have a class with constructor that takes an array like this:
public struct MyStruct{
Car car;
Boolean processed;
}
public class MyClass{
private MyStruct[] mCarStructs;
public MyClass(Car[] cars)
{
//So the only reason I pass Car[] in is to use it to
//populate my array of structs
mCarStructs = new MyStruct[cars.Length];
for (int i = 0; i < cars.Length; i++)
{
myCarStructs[i].car = cars[i];
myCarStructs[i].processed = false;
}
}
public void processCar(...)
{
if (DoProcess(myCarStructs[i].car))
{
myCarStructs[i].processed = true;
}
}
...
...
}
My understanding is that arrays are passed in by default as a reference. So, I dont think this is a leak and the reference passed in constructor will be nulled once constructor code completes.
So, there is no leak. Is this correct?
Thanks,
Arrays are not passed by reference, arrays are references. The reference to the array is passed by value.
As for memory leaks, the Garbage Collector is going to clean up all managed objects as soon as there are no longer any references to those objects; you don't need to worry about explicit memory management except in those cases where you're dealing with unmanaged memory (which you're not doing here).
Is there any way to set the life cycle of a static variable - ie: how long it's kept alive before being reset? I was hoping there may be an attribute which can be applied.
The lifetime of a value in a Static variables is the same as it's containing AppDomain. Ie. if you get a new AppDomain (because your IIS application restarts), you get a new copy of the static variable.
Static members are associated with the type itself, not with an instance of the type. Therefore their lifecycle is limited to the timing and ordering of their creation, and they don't get "reset" by instances of the type.
In my case, as I'm using ASP.NET, the item in question should remain 'live' for the lifecycle of one request, so after thinking about it the HttpContext["Items"] collection would be best. Eg, instead if:
private static SomeObject _books;
protected static SomeObject Books
{
get
{
if (_books == null) {
_books = new SomeObject();
}
return _books ;
}
}
protected static SomeObject AVariable
{
get
{
SomeObject books = HttpContext.Current.Items["books"] as SomeObject;
if (books == null) {
books = new SomeObject();
HttpContext.Current.Items["books"] = books;
}
return books;
}
}
A static variable is held for the lifespan of the application and shared between all threads. It is only reset when the application restarts (a web.config change for example).
If this is for something like caching I'd suggest setting a timer to update the value at regular intervals.