1

I have a puzzle about singleton mode freeing object memory in C# between in C++; Here C++ Code:

#include<iostream>
using namespace std;
class Rocket
{
private:
    Rocket() { speed = 100; }
    ~Rocket() {}
    static Rocket* ms_rocket;
public:
    int speed;
    static Rocket*ShareRocket()
    {
        if (ms_rocket == NULL)
            ms_rocket = new Rocket();
        return ms_rocket;
    }
    static void Close()
    {
        if (ms_rocket != NULL)
            delete ms_rocket;
    }
};
Rocket *Rocket::ms_rocket = NULL;
int main()
{
    Rocket* p =  Rocket::ShareRocket();
    p->speed = 100;
    cout << p->speed << endl;
    Rocket::Close();
    cout << p->speed << endl;
    getchar();
}

When I use Rocket::Close(), the memory space which ms_rocket pointed to will be freed, ms_rocket become a wild pointer, and the second "cout<age<<endl" show is not 100, but when I use C# , I also use Dispose(), but still show 100. here the C# code:

    class A : IDisposable
    {
        public int age;
        public A() {  }
        public void Run()
        {
            Console.WriteLine("Run");
        }
        #region IDisposable Support
        private bool disposedValue = false; 

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    Console.WriteLine("A is release");
                }
                disposedValue = true;

            }
        }
        public void Dispose()
        {
            Dispose(true);
        }
        #endregion
    }

    class B
    {
        static A a;
        private B() { }
        public static A Intance
        {
            get
            {
                if (a == null)
                    a = new A();
                return a;
            }
        }

    }
    class Class1
    {

        public static void Main(string[] args)
        {
            A a = B.Intance;
            a.age =100;
            Console.WriteLine(a.age);
            a.Dispose();
            A a1 = B.Intance;
            Console.WriteLine(a1.age);
            Console.Read();
        }
    }

In C#, I think when I use Dispose(), the memory('a' object in B singleton) will be released, but in the second access, the age value should not be 100, and the static variable 'a' will become like a wild pointer. Who can tell me why?

jzian
  • 23
  • 5
  • 4
    C# has a _garbage collector_ which deletes things when it wants, in C++, you are the _garbage collector_ and you decide when and what to delete, so basically I guess in this case _garbage collector_ didn't free the memory you are talking about. Also, in C++, you also _may_ have the same value if you'll try to print it out, but in that case it's just an undefined behavior, not some valid thing. – Karen Melikyan Apr 26 '21 at 15:20
  • What Karen said, but also GC in C# does have a method where in the first pass it flags objects for garbage collection. Even if you call `GC.Collect`, it will only flag the items on the first pass. On subsequent passes, it will eventually dealloc the memory for it. – Matthew M. Apr 26 '21 at 15:26
  • When you `delete` you're saying, "I don't need this anymore and promise not to use it." If you break the promise, that's on you. Because any checking to make sure you keep your promises would slow down a program where the promise was kept, and that's all correctly written programs, C++ requires no checking. – user4581301 Apr 26 '21 at 15:27
  • @KarenMelikyan, @jzian, Also Dispose() doesn't release anything. It's so you can do cleanup on unmanaged resources. Based on your example, if you want the GarbageCollector to cleanup A eventually, you need for some way to set it to null on B. IE, add a setter to the B.Instance property where you do: `B.Instance = null`. – B.O.B. Apr 26 '21 at 15:27
  • Side note: [A generally better, thread-safe C++ Singleton](https://stackoverflow.com/a/1008289/4581301). Note the complete absence of `new` and `delete`. This deviates from the question's code because once created, only program exit can destroy the object. ON the other hand, you don't need a dispose method. That's done for you. – user4581301 Apr 26 '21 at 15:35

1 Answers1

0

In C# Dispose mainly is used to release unmanaged resources as soon as they are not needed and not to free the memory occupied by object itself - it is handled by garbage collector which will free (when GC will decide that it needs to run) it only when it will become unaccessible from so called GC roots (and static variables are one of the GC roots, so B.Intance will hold the reference to this instance of A in the heap).

So first of all to free the memory taken by current instance of A you will need to set B.Instance to null (and wait for GC to run).

Also fundamentals of garbage collection in CLR can be useful.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • 1
    C++ Note: dispose's job is handled by [RAII](https://stackoverflow.com/questions/2321511/what-is-meant-by-resource-acquisition-is-initialization-raii) in C++. Because in C++ you know exactly when an object is destroyed (it goes out of scope, it's manager goes out of scope, or you call `delete`) and it happens immediately, you seldom need a dispose function. – user4581301 Apr 26 '21 at 15:31