The .NET Garbage collector - c#

This is a very basic question. I am debugging some memory leaks and got totally confused. Suppose I have the following:
public class ObjectData : IDataObject
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ObjectRepository<T> where T : IDataObject
{
private Dictionary<int, T> Objects;
public ObjectRepository()
{
Objects = new Dictionary<int, T>();
// load Data
}
public T GetDataObject(int id);
{
return Objects[id];
}
public Reset()
{
Objects = new Dictionary<int, T>();;
}
}
Now suppose I have the following program flow:
public Main()
{
var DataRepository = new ObjectRepository<ObjectData>();
// Constructor called and Data loaded
var myObject = DataRepository.GetDataObject(1);
DataRepository.Reset();
// Call manually the garbage collector or leave it
// Program flow continue after this
}
The question is, will the garbage collector get rid of the collection initially created by the constructor? Or it will not because one of the elements is still referenced in the program flow (myObject)?

It will be collected (eventually), since there is no more references to it. Getting a reference to something in a dictionary doesn't give you any reference to the dictionary itself! Unless that object somehow references the dictionary internally, that is.

To answer such questions ask yourself: Who is referencing the object in question (in this case the overwritten dictionary)?
DataRepository is not. You overwrote the object reference pointing to the old dictionary.
myObject is not because ObjectData does not have any field of type dictionary. It can't reference a dictionary.
Nobody is left to reference the old dictionary.

After your call to Reset, there is no strong references to your initial dictionary. Thus, it will be elected for garbage collection.
Or it will not because one of the elements is still referenced in the program flow (myObject)?
It doesn't matter which objects the dictionary refers to, what matters is who refers to the dictionary. In this case, no one. It's perfectly possible for the dictionary to be collected while its contents are still alive.

Related

Navigating between ContentPages with Prism in Xamarin Forms maintains NavigationParameters

Using the NavigationParameters collection within Prism, we are passing an object from one ContentPage to another ContentPage which displays as a modal.
The modal allows a user to edit the data. If the user decides to cancel the edit form, we call:
NavigationService.GoBackAsync(null, true).
Once navigated back to the previous page, the original property that was passed through to the modal has updated with the edited values without setting it.
Are NavigationParameters passed as a reference within NavigateAsync? What’s the best way of preventing this from happening?
Using the NavigationParameters collection within Prism, we are passing an object [...] [Emphasis mine]
You are setting an object in the NavigationParameters. Instances of classes (objects) are passed by reference in C#, instances of structures are passed by value. For structures there are semantics to copy and compare values (i.e. all public properties are copied and compared respectively), but for classes there are no similar semantics.
Please see the documentation:
Because classes are reference types, a variable of a class object holds a reference to the address of the object on the managed heap. If a second object of the same type is assigned to the first object, then both variables refer to the object at that address.
In order to prevent the original object being updated, you'll have to copy the object before it is manipulated (I'd copy it before passing it, but you could copy it at the target site, too). If your class contains value type properties only, a shallow copy will suffice, i.e. you create a method (or property, but this might be misleading) that returns a new object of your class with all the values copied
class MyClass
{
int Value1 { get; set; }
float Value2 { get; set; }
public MyClass Copy()
{
var copy = new MyClass()
{
Value1 = this.Value1,
Value2 = this.Value2
}
return copy;
}
}
If you object contains reference types itself, you might have to create a deep copy
class MyClass
{
MyClass2 Reference { get; set; }
public MyClass Copy()
{
var copy = new MyClass()
{
Reference = this.Reference.Copy()
}
return copy;
}
}
Of course, those will have to implement a Copy() method, too.

Updating One Object Updates the Other somehow

I have two objects, yet when i update one, the other item with the same GUID gets updated as well even though i am trying to apply a new GUID so that i can separate them out.
var completedSecond = model.CompletedTransfers.First();
var transferedTransfers = model.TransferedTransfers.First();
if (transferedTransfers.Count != 0) {
transferedTransfers.RowId = Guid.NewGuid();
}
When i run this code, the two items have the same GUID, yet when i update the second one to have a new GUID, the first object also gets that new GUID. How is this possible?
You don't have 2 objects but 2 references to the same object in memory. In C# classes are reference types meaning that your completedSecond is referencing an object in memory, that in this case is the same as the object transferedTransfers is referenceing to.
In order to get 2 different object you need to instantiate a new object
By implementing the ICloneable interface
public class MyClass : ICloneable
{
public Guid Id { get; set; }
public object Clone()
{
return new MyClass { Id = Id };
}
}
Another way is to have a copy constructor:
public class MyClass
{
public Guid Id { get; set; }
public MyClass() { }
public MyClass(MyClass other)
{
Id = other.Id;
}
}
Read this for the differences between the two ways: Copy constructor versus Clone()
In addition, when talking about coping of objects you have what is called deep-copy and shallow-copy. More on these you can find here:
Shallow copy or Deep copy?
Object.MemberwiseClone Method
That happens because the model.TransferedTransfers object is passed by reference, not by value. the variable completedSecond and transferedTransfers both points to model.CompletedTransfers. Also be aware of naming smells (transferedTranfers)

Visibility inside a class of objects created locally

Here it is a sample code in Windows Forms:
namespace WindowsFormsApplication1
{
public class contained
{
public int value;
}
public class container
{
public List<contained> c1 = new List<contained>();
public void add_contained()
{
contained tmp = new contained();
tmp.value = 1; // some default value
c1.Add(tmp);
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
container cnt = new container();
cnt.add_contained();
int i = cnt.c1[0].value; // this works, why?
}
}
}
Practically, I have a big class "container" that manages a list of complex objects "contained". There is a procedure adding a new blank object to the list - to be modified later. Now, I ran the code above and it works, but I do not understand well why.
If the procedure "add_contained" to add a default object to the list creates one locally, I expect it disappear when the procedure exits, so the list should remain with a null pointer. Instead, I can still access the object in the list, as indicated in the last line "int i=...".
Actually, I read the garbage collector is non deterministic, it is unclear what it means, it seems it does not do things in precise moments. But, that means the above code works because it is short? If I accessed the list a bit later (ie in a more complex program) it could not work?
What is the correct way to solve the problem outlined by the code above? Thanks.
When you do new contained() a new object is created and stored "somewhere".
Then a reference to it is assigned to tmp.
That same reference is in turn added to the list and you exit the method.
At that point the variable tmp is "destroyed" but the object is still in memory (because it's still referenced through the List).
If at some point you remove the list item, the reference on that object ; and there are no other reference on that object ; it becomes eligible for collection, meaning the GC can free it's memory.

Garbage Collection setting object to null [duplicate]

This question already has answers here:
Garbage Collection: Is it necessary to set large objects to null in a Dispose method?
(6 answers)
Closed 9 years ago.
Given
public class A
{
public B First { get; set; }
}
public class B
{
public C Second { get; set;}
}
public class C
{
public D Third { get; set; }
}
And somewhere in the class you have this
var testClass = new A();
//All the properties have values in it and the class D has a property value that it is holding in to the memory
//testClass.B = new B();
//etc..
What happens if you did testClass = null? What does testClass's reference now to the heap? And what about D that is holding to a value that it can't collect?
EDIT: Just to clarify, given D has an event that hasn't been unsubscribed and has 10,000 handlers. What happens to testClass = null?
When you execute testClass = null, then the object remains on the heap. But there is no longer any reference to it in your code. It is eligible for garbage collection.
Any objects which are fields of A will no longer be referenced anywhere either. They will also be eligible for garbage collection.. and so on.
(As it happens, in your specific code, the fields First, Second and Third are never assigned. They are still null, so they don't really make any difference to the discussion).
Note that this collection probably won't happen straight away - setting testClass = null won't trigger a collection in itself.
If D references unmanaged resources, then it'll still be eligible for garbage collection when you set testClass = null. But unless D implements a Finalizer (which explicitly cleans up the unmanaged resources), then it will leak.
If D is an event with lots of subscriptions, then D will still be eligible for GC, even if you never explictly unsubscribe. See this answer here.
Following on, then if the subscriptions themselves are objects which are no longer referenced anywhere else, then they too will be eligible for collection.

Can I re-use object instances to avoid allocations with protobuf-net?

Context: this is based on a question that was asked and then deleted before I could answer it - but I think it is a good question, so I've tidied it, rephrased it, and re-posted it.
In a high-throughput scenario using protobuf-net, where lots of allocations are a problem (in particular for GC), is it possible to re-use objects? For example by adding a Clear() method?
[ProtoContract]
public class MyDTO
{
[ProtoMember(1)]
public int Foo { get; set; }
[ProtoMember(2)]
public string Bar { get; set; }
[ProtoMember(3, DataFormat = DataFormat.Group)]
public List<int> Values { get { return values; } }
private readonly List<int> values = new List<int>();
public void Clear()
{
values.Clear();
Foo = 0;
Bar = null;
}
}
protobuf-net will never call your Clear() method itself, but for simple cases you can simply do this yourself, and use the Merge method (on the v1 API, or just pass the object into Deserialize in the v2 API). For example:
MyDTO obj = new MyDTO();
for(...) {
obj.Clear();
Serializer.Merge(obj, source);
}
This loads the data into the existing obj rather than creating a new object each time.
In more complex scenarios where you want to reduce the number of object allocations, and are happy to handle the object pooling / re-use yourself, then you can use a custom factory. For example, you can add a method to MyDTO such as:
// this can also accept serialization-context parameters if
// you want to pass your pool in, etc
public static MyDTO Create()
{
// try to get from the pool; only allocate new obj if necessary
return SomePool.GetMyDTO() ?? new MyDTO();
}
and, at app-startup, configure protobuf-net to know about it:
RuntimeTypeModel.Default[typeof(MyDTO)].SetFactory("Create");
(SetFactory can also accept a MethodInfo - useful if the factory method is not declared inside the type in question)
With this, what should happen is the factory method is used instead of the usual construction mechanisms. It remains, however, entirely your job to cleanse (Clear()) the objects when you are finished with them, and to return them to your pool. What is particularly nice about the factory approach is that it will work for new sub-items in lists, etc, which you can't do just from Merge.

Categories

Resources