none
Weak Reference RRS feed

  • Question

  • static WeakReference data;       

    static object GetData()

            {

             if(data == null) { data = new WeakReference(GetList()); }

              if(data.Target == null) { data.Target = GetList(); }          

              return data.Target;

            }

     

           

    static private ICollection<string> GetList()

            {

                return new List<string> { "Hello", " Word"};

            }

    When I do this all work Like I think

    GetData();

    Console.WriteLine($"{data.Target}");// Not Null           

    Console.WriteLine($"{data.IsAlive}");// True 

    Console.WriteLine();

              

    GC.Collect();

               

    Console.WriteLine($"{data.Target}");//Null           

    Console.WriteLine($"{data.IsAlive}");//False          


     But When I Write this.

    GetData();

    Console.WriteLine($"{data.Target}");// Not Null           

    Console.WriteLine($"{data.IsAlive}");// True 

    Console.WriteLine();

              

    GC.Collect();

               

    Console.WriteLine($"{data.Target}");//Not Null WHY

    Console.WriteLine($"{data.IsAlive}");//TRUE WHY

    varobj = GetData();

               

    foreach (var item in (ICollection<string>)obj)

                {

    Console.WriteLine(item);

                }

               

    Console.WriteLine();

               

    GC.Collect();

                 

    Console.WriteLine($"{data.Target}");//NOT NULL

    Console.WriteLine($"{data.IsAlive}");//TRUE


               

    foreach (var item in (ICollection<string>)obj)

                {

    Console.WriteLine(item);//Hello World

                }

    I see another situation WHY?



    • Edited by Ahlompys Wednesday, May 8, 2019 1:48 PM
    Wednesday, May 8, 2019 12:35 PM

Answers

  • You're trying to make assumptions about how the GC works that simply aren't true. WeakReference doesn't make your data collectable. The GC looks at all the references and gets rid of items that aren't needed anymore but it uses generations and can follow other rules such that your object won't necessarily get cleaned up immediately. All WeakReference does is tell the GC that the underlying object shouldn't be counted as referenced by that instance. It can still be referenced elsewhere.

    You need to be real careful about calling GC. Many people tend to create an object in a local variable and then call GC and expect it to get cleaned up but it won't (and will likely get promoted in the process). Variables are "referenced" for the life of the function that they are used in. This isn't based on the arbitrary language scoping rules but the general runtime rules.

    To help speed the demise of the object you could try putting your call to create the object in a function and then call that function. But, again, there are no guarantees it'll get GCed immediately.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by Ahlompys Wednesday, May 8, 2019 5:35 PM
    Wednesday, May 8, 2019 2:15 PM
    Moderator
  • When you call Collect it tells the GC to run. The GC then runs and does what is discussed here. The purpose of WeakReference is to allow you to "reference" an object but the GC will not treat it as a reference. Therefore if the only "references" you have left to a value happens to be stored in WeakReference then the GC can clean it up like it would any other object.

    As Karen mentioned, you didn't put your code into the code editor so it is hard to see what is happening. You mention the first block of code before the GC collect works correctly. Not surprised by this. You then add more code to the method and it suddenly stops working. That's because you're still referencing the underlying object in the current function. The GC knows the object is still being referenced and therefore cannot be freed yet. That's what I meant by the language scope thing.  In your code you have a call to `GetData` that returns back the list you hoped was weakly referenced. That is going to be the same list that `data.Target` references. Let's mix things up. 

    static void Main ( string[] args )
    {
        GetData();
    
        Console.WriteLine($"{data.Target}");// Not Null            
        Console.WriteLine($"{data.IsAlive}");// True 
        Console.WriteLine();
    
        GC.Collect();
    
        Console.WriteLine($"{data.Target}");//Not Null WHY
        Console.WriteLine($"{data.IsAlive}");//TRUE WHY
    
        //Remaining references to Target will be in a different function
        Foo();
    
        //May or may not be available at this point so force a collection
        GC.Collect();
    
        //Should be gone now because we don't have any more references to it in scope
        Console.WriteLine($"{data.Target}");
        Console.WriteLine($"{data.IsAlive}");
    }
    
    private static void Foo ()
    {
        var obj = GetData();
    
        foreach (var item in (ICollection<string>)obj)
        {
    
            Console.WriteLine(item);
        }
    
        Console.WriteLine();
    
        GC.Collect();
    
        Console.WriteLine($"{data.Target}");//NOT NULL
        Console.WriteLine($"{data.IsAlive}");//TRUE
    
        foreach (var item in (ICollection<string>)obj)
        {
            Console.WriteLine(item);//Hello World
        }
    }
    Note that for demo purposes your code might be useful to look at but we would absolutely never do this in any sort of production code. The purpose of WeakReference is to allow us to keep a "reference" to an object but not keep it from getting GC'ed. The code you wrote would absolutely not be something that you'd ever do in production because it is trying to muck with the reference rather than using a local variable. A more realistic scenario would be a WeakReference as a field that a class might reference. When it is not alive the class would "reinitialize" it. We wouldn't be mixing collections and reads in the same method as it wouldn't make sense.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by Ahlompys Thursday, May 9, 2019 8:27 AM
    Wednesday, May 8, 2019 6:02 PM
    Moderator

All replies

  • Hello,

    Please edit your post and place well formatted code into code blocks. Also, please expand on what you mean by "I see another situation WHY?"

    Code button to insert code.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Wednesday, May 8, 2019 1:30 PM
    Moderator
  • You're trying to make assumptions about how the GC works that simply aren't true. WeakReference doesn't make your data collectable. The GC looks at all the references and gets rid of items that aren't needed anymore but it uses generations and can follow other rules such that your object won't necessarily get cleaned up immediately. All WeakReference does is tell the GC that the underlying object shouldn't be counted as referenced by that instance. It can still be referenced elsewhere.

    You need to be real careful about calling GC. Many people tend to create an object in a local variable and then call GC and expect it to get cleaned up but it won't (and will likely get promoted in the process). Variables are "referenced" for the life of the function that they are used in. This isn't based on the arbitrary language scoping rules but the general runtime rules.

    To help speed the demise of the object you could try putting your call to create the object in a function and then call that function. But, again, there are no guarantees it'll get GCed immediately.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by Ahlompys Wednesday, May 8, 2019 5:35 PM
    Wednesday, May 8, 2019 2:15 PM
    Moderator
  • Good evening Michael Taylor

    You want tell me, that when I call GC.Collect(). this is don't mean that garbage will be collected immidiatlly and clean WeakReference target?

    I thinked, when I call GC.Collect() this is force clear heap. And first example show me this. But I'm not undenstanded Why when I add in first Example more code first path not work like earlier.


    Wednesday, May 8, 2019 5:34 PM
  • When you call Collect it tells the GC to run. The GC then runs and does what is discussed here. The purpose of WeakReference is to allow you to "reference" an object but the GC will not treat it as a reference. Therefore if the only "references" you have left to a value happens to be stored in WeakReference then the GC can clean it up like it would any other object.

    As Karen mentioned, you didn't put your code into the code editor so it is hard to see what is happening. You mention the first block of code before the GC collect works correctly. Not surprised by this. You then add more code to the method and it suddenly stops working. That's because you're still referencing the underlying object in the current function. The GC knows the object is still being referenced and therefore cannot be freed yet. That's what I meant by the language scope thing.  In your code you have a call to `GetData` that returns back the list you hoped was weakly referenced. That is going to be the same list that `data.Target` references. Let's mix things up. 

    static void Main ( string[] args )
    {
        GetData();
    
        Console.WriteLine($"{data.Target}");// Not Null            
        Console.WriteLine($"{data.IsAlive}");// True 
        Console.WriteLine();
    
        GC.Collect();
    
        Console.WriteLine($"{data.Target}");//Not Null WHY
        Console.WriteLine($"{data.IsAlive}");//TRUE WHY
    
        //Remaining references to Target will be in a different function
        Foo();
    
        //May or may not be available at this point so force a collection
        GC.Collect();
    
        //Should be gone now because we don't have any more references to it in scope
        Console.WriteLine($"{data.Target}");
        Console.WriteLine($"{data.IsAlive}");
    }
    
    private static void Foo ()
    {
        var obj = GetData();
    
        foreach (var item in (ICollection<string>)obj)
        {
    
            Console.WriteLine(item);
        }
    
        Console.WriteLine();
    
        GC.Collect();
    
        Console.WriteLine($"{data.Target}");//NOT NULL
        Console.WriteLine($"{data.IsAlive}");//TRUE
    
        foreach (var item in (ICollection<string>)obj)
        {
            Console.WriteLine(item);//Hello World
        }
    }
    Note that for demo purposes your code might be useful to look at but we would absolutely never do this in any sort of production code. The purpose of WeakReference is to allow us to keep a "reference" to an object but not keep it from getting GC'ed. The code you wrote would absolutely not be something that you'd ever do in production because it is trying to muck with the reference rather than using a local variable. A more realistic scenario would be a WeakReference as a field that a class might reference. When it is not alive the class would "reinitialize" it. We wouldn't be mixing collections and reads in the same method as it wouldn't make sense.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by Ahlompys Thursday, May 9, 2019 8:27 AM
    Wednesday, May 8, 2019 6:02 PM
    Moderator