Static Methods Memory Consumption - c#

I have the following class with the following methods:
public class Foo
{
public string A {get;set;}
public static Foo New(string a)
{
Foo newFoo = new Foo();
newFoo.A = a;
return newFoo;
}
}
public class Bar
{
public void SomeMethod()
{
...
Foo anotherFoo = Foo.New("a");
....
}
}
If the Bar class creates Foo during a process using the above code, will Foo ever go out scope and get garbage collected or will Foo (because it is using a static method) continue to have a reference to variable newFoo and therefore anotherFoo will never go out of scope?

The presence of static methods doesn't impact an object's eligibility for GC, only references to that object do. In your case anotherFoo will be the only reference. The reference newFoo goes out of scope when the method returns, popping off the stack.
Local variables inside static methods are not themselves "static", when the method returns, those locals will be popped from the execution stack the same as non static methods.
The underlying object behind anotherFoo will become eligible for GC when SomeMethod returns (well, the compiler is more aggressive and can make it GC-able when anotherFoo is no longer used in the code).

a leaves scope as soon as Foo.New() completes. The reference to newFoo is returned, and then newFoo goes out of scope. SomeMethod still has a reference to that instance via the anotherFoo reference, so that reference is not available for garbage collection until SomeMethod completes, unless that reference is saved.

Classes never "goes out of scope". Instance (references) do. As for the newFoo reference, it goes out of scope when the method New ends as will anotherFoo when the SomeMethod method ends.
The fact that the method is static does not changes anything, in fact, you coudl even have a static variable in Foo that it wouldn't change anything because static variable are create on a separate heap called "high frequency heap" where GC obviously never collect anything.

Related

Unclear behavior by Garbage Collector while collecting instance properties or fields of reachable object

Till today I was thinking that members of reachable objects are also considered to be reachable.
But, today I found one behavior which creates a problem for us either when Optimize Code is checked or application is executed in Release Mode. It is clear that, release mode comes down to the code optimization as well. So, it seems code optimization is reason for this behavior.
Let's take a look to that code:
public class Demo
{
public Action myDelWithMethod = null;
public Demo()
{
myDelWithMethod = new Action(Method);
// ... Pass it to unmanaged library, which will save that delegate and execute during some lifetime
// Check whether object is alive or not after GC
var reference = new WeakReference(myDelWithMethod, false);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
Console.WriteLine(reference.IsAlive);
// end - Check whether object is alive or not after GC
}
private void Method() { }
}
I simplified code a bit. Actually, we are using our special delegate, not Action. But the behavior is same. This code is written in mind with "members of reachable objects are also considered to be reachable". But, that delegate will be collected by GC asap. And we have to pass it to some unmanaged library, which will use it for some time.
You can test demo by just adding that line to the Main method:
var p = new Demo();
I can understand the reason of that optimization, but what is the recommended way to prevent such case without creating another function which will use that variable myDelWithMethod which will be called from some place? One, option I found that, it will work if I will set myDelWithMethod in the constructor like so:
myDelWithMethod = () => { };
Then, it won't be collected until owning instance is collected. It seems it can't optimize code in the same way, if lambda expression is setted as a value.
So, will be happy to hear your thoughts. Here are my questions:
Is it right that, members of reachable objects are also considered to
be reachable?
Why it is not collected in case of lambda expression?
Any recommended ways to prevent collection in such cases?
However strange this would sound, JIT is able to treat an object as unreachable even if the object's instance method is being executed - including constructors.
An example would be the following code:
static void Main(string[] args)
{
SomeClass sc = new SomeClass() { Field = new Random().Next() };
sc.DoSomethingElse();
}
class SomeClass
{
public int Field;
public void DoSomethingElse()
{
Console.WriteLine(this.Field.ToString());
// LINE 2: further code, possibly triggering GC
Console.WriteLine("Am I dead?");
}
~SomeClass()
{
Console.WriteLine("Killing...");
}
}
that may print:
615323
Killing...
Am I dead?
This is because of inlining and Eager Root Collection technique - DoSomethingElse method do not use any SomeClass fields, so SomeClass instance is no longer needed after LINE 2.
This happens to code in your constructor. After // ... Pass it to unmanaged library line your Demo instance becomes unreachable, thus its field myDelWithMethod. This answers the first question.
The case of empty lamba expression is different because in such case this lambda is cached in a static field, always reachable:
public class Demo
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Action <>9__1_0;
internal void <.ctor>b__1_0()
{
}
}
public Action myDelWithMethod;
public Demo()
{
myDelWithMethod = (<>c.<>9__1_0 ?? (<>c.<>9__1_0 = new Action(<>c.<>9.<.ctor>b__1_0)));
}
}
Regarding recommended ways in such scenarios, you need to make sure Demo has lifetime long enough to cover all unmanaged code execution. This really depends on your code architecture. You may make Demo static, or use it in a controlled scope related to the unmanaged code scope. It really depends.

Method returns class reference even after termination

I have just started learning C#7.0 from the documentation. I learnt that Class is a reference type. But how can a method return a reference to an object that is already destroyed.
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
public class Program
{
public static void Main()
{
Test b = GetObj();
Console.WriteLine(b.val);
Console.ReadLine();
}
public class Test
{
public int val;
}
public static Test GetObj()
{
Test t = new Test();
t.val = 100;
return t;
}
}
}
Here, method GetObj creates a Test object, and returns it. According to documentation, only a reference to it is returned. So after the function call, t should be collected as garbage, and so b should reference nothing.
But the code still prints 100. Why?
So after the function call,"t" should be collected as garbage, and so "b" should reference nothing.
No. The garbage collector knows how many variables are still referencing that instance, so it isn't garbage collected at all. When there are no variables referencing the instance any more, the garbage collector will kick in.
Not exactly.
When GetObj() is done executing, what is destroyed is the pointer t, not the actual object of type Test.
As you go up the stack, b now points to the object, so the object is not collected because there is a reference to it.
When Main() is done executing, the pointer b will go out of scope and nothing will point to the object anymore so the garbage collector will be able to pick it up (in this case, the end of the program execution).

Does assigning an object to other creates a copy?

I tried with the below code, I got the output as 1000. I heard assigning object must share the reference instead of copying the entire object memory. Here the result is different.Can anyone help.
public aaaaa ad = new aaaaa();
static void Main(string[] args)
{
Program p = new Program();
p.fun1();
p.fun2();
}
public void fun1()
{
using(smallclass s = new smallclass())
{
s.j = 1000;
ad.fun1(s);
}
}
public void fun2()
{
ad.fun2();
}
public class aaaaa
{
public smallclass h = new smallclass();
public void fun1(smallclass d)
{
h = d;
}
public void fun2()
{
Console.WriteLine(h.j);
}
}
public class smallclass:IDisposable
{
public int j = 9;
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
Update:
I expect an object reference exception as the referenced memory is disposed in p.fun1();
Here is an simple example how assinging works
using System;
namespace ConsoleApplication1
{
internal class Program
{
private static smallclass objA = new smallclass();
private static smallclass objB = new smallclass();
private static void Main(string[] args)
{
showValues();
objA.value = 1000;
showValues();
objB = objA;
showValues();
objA.value = 1055;
showValues();
}
private static void showValues()
{
Console.WriteLine("objA.value: " + objA.value);
Console.WriteLine("objB.value: " + objB.value);
Console.ReadLine();
}
}
internal class smallclass : IDisposable
{
public int value = 0;
public void Dispose()
{
//Here you can remove eventHandlers
//or do some other stuff before the GC will play with it
}
}
}
Like you can see
first we create 2 objects objA and objB
than we show the values like expected they are both 0
after that we increase the value of objA to 1000
the value of objA a is 1000 and the value of objB remains at 0
NOW we assingning objA and objB
so the value of objB got also 1000
if we now change the value of objA to 1055
the value of objB get also changed
because objB is no more an separate object it now holds the same
reference like objA does
EDIT
And now i will show you how you get your Error based on your example
change your aaaaa class to:
public class aaaaa
{
public WeakReference<smallclass> h;
public void fun1(smallclass d)
{
h = new WeakReference<smallclass>(d);
}
public void fun2()
{
smallclass k;
if(h.TryGetTarget(out k))
Console.WriteLine(k.j);
else
Console.WriteLine("ERROR ERRROR ERROR");
}
}
and modify your static void Main(string[] args) to:
static void Main(string[] args)
{
Program p = new Program();
p.fun1();
GC.Collect();
p.fun2();
Console.Read();
}
Ok lets get through the changes
we are using the WeakReference<T> (you could also use WeakReference)
if the GC now comes across our object he can't find a StrongReference so can Collect it
now to the GC.Collect() YOU need to call it because it forced the GC to do his work (now at this moment)
and remember like i told you before IDisposable will get called from the GC before he destroys the object (AFAIK) so there is the place to put all the stuff that need to be done before the object will get destroyed
No, assingning is not a "new" statement, it copies.... a reference, it does not create a new object. For a class.
For a struct, it does so.
I suggest learning C# by reading the documentation or a book - those basics are normally handled to great detail in those.
You will not go far wrong if you think of every reference type variable, field, parameter, array slot, or other such storage location, has holding either "null", or "object #24601" [or some other number]. There are really only a handful things that can be done with references:
You may create a null reference
You may ask the system to create a new object and return a reference to it
You may copy one reference to another
You may check whether two references are equal to each other, or whether one is equal to null.
You may ask the system to perform some action upon the object identified by a reference
If myCar is a variable of some reference type, a statement like myCar.Color = CarColors.Blue won't affect the variable myCar at all. Instead, it will observe that myCar holds [e.g.] "Object #8675309", and then ask the system to access the Color property or field of object #8675309. Conversely, if otherCar happens to hold "object #90210", a statement of the form otherCar=myCar won't do anything with object #8675309, nor object #90210, but will instead replace the "90210" stored in otherCar with "8675309".
Objects are guaranteed to exist as long as any form of reference to them exists, but if there are two objects which, although referenced by each other, are not referenced by anything else in the universe, both objects may simultaneously cease to exist. This rule is absolute, but there are a couple of twists: code may request a WeakReference to an object; an object is guaranteed to exist as long as a weak reference to it exists, but if the system discovers that no strong references to an object exist, it will invalidate every WeakReference to it. Further, the system keeps a list of all objects that have would like to be notified if they are abandoned. If the system finds that this list holds the only reference to an object, it will move the object to a strongly-referenced list of objects whose Finalize method should run at the first convenient opportunity. When the object's Finalize method is run, the reference will be removed from that latter list. If no reference to the object has been stored anywhere in the mean time, the object will cease to exist.
I have replaced GC.SuppressFinalize with GC.Collect() in dispose function, however this is not freeing the memory.. and am receiving 1000 as a result.
I guess, as it holds other reference(the variable h), GC will not free the memory, even if we invoked it explicit.
So we can very well pass and assign the objects irrespective of the allocated(new) object going out of scope.
Please correct me If i am wrong.

In C#, do all static variables get initialized before the main() method is called?

The ones I am particularly concerned about are:
static variables in classes that are defined in referenced/dependency classes, contained in external DLLs. In my example, none of the types in that third party assembly is reference until later in the program. (let's say 5 min into execution).
Will the static variables of that third-party assembly only be loaded then?
Thanks,
rui
according to C# spec which says:
If a static constructor exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class. The example
whiteout a static constructor you can not predict exactly when a static variable is initialized but they are guaranteed to be initialized before their first use. but for sure they are not initialized before you reference their assemblies
All static fields are initialized before they are first used. This can be done by a type initializer (static constructor) explicitly declared or implicitly provided by the compiler. Static fields that do not have a value assigned in the class declaration will be initialized to the default value of their corresponding type.
Be careful if your static fields are object references whose constructors may throw exceptions:
class Foo
{
public Foo() { throw new Exception("boom"); }
}
class Bar
{
private static Foo baz = new Foo();
public Bar()
{
//trying to create a Bar will throw TypeInitializationException
}
public static void BarNone()
{
//trying to call a static method on Bar will throw TypeInitializationException
}
}
You'll get a TypeInitializationException when Bar is first used (either constructed or when a static method on Bar is called), as shown above.

Some questions about static constructors, methods and fields

I have some questions about behaviour of static members:
1) Is there a difference when initializing static fields and static constructors? As of my knowledge static fields are initialized with program execution. Does members of static constructors behave same way, or they are initialized on first use:
MyClass.myStaticField;
or I must initialize MyClass first:
Myclass m = new MyClass(); // static constructor is called
MyClass.myStaticField; // and after that
2) As I do recall, static fields are not garbage collected? So is this a reason, why I should not be instanciating static methods? When I've read about this topic, most of the people claims, that you should use static methods when, you can choose between static and non-static.
3) Is there any issues that must be pointed when you derive a class from parent class having static constructor?
4) Just of a curiosity, can you dispose static member?
The difference between static field and constructor initialization is a bit complex as it's changed between framework versions. Jon did an indepth blog article on this subject that you should take a look at.
http://msmvps.com/blogs/jon_skeet/archive/2010/01/26/type-initialization-changes-in-net-4-0.aspx
Static Fields are garbage collected just like normal values. That is they are collected when they can no longer be accessed. This can happen in a number of scenarios the most common of which is when an AppDomain unloads. Static fields are specific to an AppDomain so once it unloads it's members are eligable for collection (this may be different for AppDomain neutral types but I don't believe so).
It's perfectly legal to Dispose a static member although it can lead to some issues if you leave the disposed value in the field and hence accessible to the rest of the application (which may not realize it's disposed)
Static methods are not immune from garbage collection. Use them all you like.
A static field normally isn't garbage collected because it doesn't go out of scope. However, if you were to set a static field to null, the instance it used to reference would then be a candidate for garbage collection. You could even call Dispose on a static field before nulling it out.
Static and instance (non-static) fields have very different meanings, and it is important to understand them before deciding which to use.
A static variable or method belongs to a class, not to a particular instance of the class. There is one copy of it per class (no matter how many instances you create) and it can be accessed without an instance of the class. For example,
public class MyClass {
static int myInt = 5;
}
System.out.println(MyClass.myInt); // this prints 5
MyClass.myInt = 10;
System.out.println(MyClass.myInt); // this prints 10
An instance variable requires an instance of the class
public class MyClass {
private int myInt2;
public void setMyInt2(int val) {
myInt2 = val;
}
public int getMyInt2() {
return myInt2;
}
}
MyClass m1 = new MyClass();
MyClass m2 = new MyClass();
System.out.println(m1.getMyInt2()); // prints 0, the default value
System.out.println(m2.getMyInt2()); // prints 0, the default value
m1.setMyInt2(3);
m2.setMyInt2(5);
// each object operates on its own instance of the variable
System.out.println(m1.getMyInt2()); // prints 3
System.out.println(m2.getMyInt2()); // prints 5
Also, there is no such thing as a static constructor. There are constructors as well as static initializer blocks. A static initializer block is written as:
static {
// initialize some static members here
}
In general, use instance variables/methods when the values affect an individual instance of an object, and use static variables and methods when they do not.
You've tagged this as Java too, so a couple of Java perspectives.
1). In Java there is no concept of a static constructor, instead you can define blocks of code as static and they are run at the time the Class is prepared for use - after all, static fields are shared by all instances of the Class and so need t be initialised before we have any working instances.
2). Don't think of fields, static or otherwise, as being garbage collected - it's objects that get garbage collected. So if you have:
class MyClass {
private static OneThing x = new OneThing();
private Another y = new Another();
}
// some code
MyClass m = new MyClass(); // creates instance of MyClass
m = null;
// no one now references that instance of MyClass
You're not garbage collecting x and y, you're garbage collecting the OneThing and Another instances. This will happen when there are no references to those objects.
In the case of the Another referenced by y, that happens when the MyClass instance itself is garbage collected. But OneThing referenced by x will still be referenced for so long as MyClass is known to the JVM. BUT, classes themselves can be garbage collected, so it is possible for eventually that x reference to be removed and the OneThing object to be garbage collected.
Static constructors/initializers all happen at the same time (though fields get initialzed based on when they get accessed.)
Static methods are never instantiated -- they represent behavior, not state. Therefore they do not participate in garbage collection.
No. The base class' static constructor will be called, but that's hardly an "issue".
What do you mean by dispose? C# IDisposable? The answer is yes if the static field is holding an instance of something that implements that interface.
With regards to #1, it's intuitively obvious in Java anyway that you don't need to create instances of the class to use the static members. It would prevent the ability to have a class that is not meant to be instantiated (e.g. java.util.Collections).
Plus you'd have a contradiction with the most common singleton pattern:
public SomeSingletonClass {
public static final SomeSingletonClass instance = new SomeSingletonClass();
private SomeSingletonClass() {}
}

Categories

Resources