How do i explicitly clear the byte[]

36,486

Solution 1

How do you know they are not being collected? The code you provide is fine, and it should become eligible for collection if you don't have any dangling references to it.

Explicitly, you can clear a reference by

outputMessage = null;

and you can hint the GC that it should do its job with this:

GC.Collect();

However, there's no guarantee that your object will get collected, and manually messing with the GC is usually not needed.

If you are adding a new event handler all the time, are you deleting any old ones? If not, then they are still keeping the reference for you.

EDIT: for clarity, and for new info by OP

Solution 2

Ensure that you have no references to your array. Examine that you have not an assignment to another variable that keeps the array in memory.

Do you leave the focus of your outputMessage?
- If it is declared inside a method: Do you leave it or do you have some (intendet) endless loop and remain in it?
- If it is declared global inside a class object: Does your complete class remain in memory by a reference to this?

Solution 3

Consider this: Is it possible to encapsulate your byte[] in a class that implements IDisposable? After use, you can dispose your object by explicitly calling Dispose(). I'm not sure if this guides you to the solution, but it would be my next attempt.

Solution 4

When a managed array leaves scope it gets flagged for garbage collection. If the array is of a value type the deallocation of items is quick but doesn't happen until the array gets collected. Remember, byte is a value type but byte[] is a reference type.

Here's a quick sample that illustrates:

void Main()
{
    const int LOOPS = 5;
    {
        Console.WriteLine("When the arrays are kept inside the method's scope:");
        Console.WriteLine(String.Format("     GC Memory: {0:N0} bytes (starting memory)", GC.GetTotalMemory(false)));
        for(int i = 0; i < LOOPS; i++)
            this.AllocateArray(i);
        Console.WriteLine(String.Format("     GC Memory: {0:N0} bytes (exited local scope)", GC.GetTotalMemory(false)));
        Console.WriteLine(String.Format("     GC Memory: {0:N0} bytes (after GC collection ran)", GC.GetTotalMemory(true)));

        Console.WriteLine("\nWhen the arrays are outside the method's scope:");
        Console.WriteLine(String.Format("     GC Memory: {0:N0} bytes (starting memory)", GC.GetTotalMemory(false)));
        var arrays = new byte[LOOPS][];
        for(int i = 0; i < LOOPS; i++)
            this.AllocateArray(i, arrays);
        Console.WriteLine(String.Format("     GC Memory: {0:N0} bytes (exited local scope)", GC.GetTotalMemory(false)));
        Console.WriteLine(String.Format("     GC Memory: {0:N0} bytes (after GC collection ran)", GC.GetTotalMemory(true)));
        arrays[0][0] = 1; // Prevent the arrays from being optimized away
    }
    Console.WriteLine("\nAll scopes exited:");
        Console.WriteLine(String.Format("     GC Memory: {0:N0} bytes (before GC runs)", GC.GetTotalMemory(false)));
        Console.WriteLine(String.Format("     GC Memory: {0:N0} bytes (after GC collection ran)", GC.GetTotalMemory(true)));
}

public void AllocateArray(int run)
{
    var array = new byte[20000000];
    Thread.Sleep(100); // Simulate work..
    Console.WriteLine(String.Format("[{0}] GC Memory: {1:N0} bytes (local array allocated)", run+1, GC.GetTotalMemory(false)));
    array[0] = 1; // Prevent the array from being optimized away
}

public void AllocateArray(int run, byte[][] arrays)
{
    arrays[run] = new byte[20000000];
    Thread.Sleep(100); // Simulate work..
    Console.WriteLine(String.Format("[{0}] GC Memory: {1:N0} bytes (array allocated)", run+1, GC.GetTotalMemory(false)));
}

The output from this looks something like this (exact results will vary):

When the arrays are kept inside the method's scope:
     GC Memory: 24,576,232 bytes (starting memory)
[1] GC Memory: 45,002,324 bytes (local array allocated)
[2] GC Memory: 44,845,548 bytes (local array allocated)
[3] GC Memory: 64,574,296 bytes (local array allocated)
[4] GC Memory: 64,959,472 bytes (local array allocated)
[5] GC Memory: 44,675,340 bytes (local array allocated)
     GC Memory: 44,675,340 bytes (exited local scope)
     GC Memory: 24,347,296 bytes (after GC collection ran)

When the arrays are outside the method's scope:
     GC Memory: 24,355,488 bytes (starting memory)
[1] GC Memory: 44,467,612 bytes (array allocated)
[2] GC Memory: 64,681,980 bytes (array allocated)
[3] GC Memory: 85,493,004 bytes (array allocated)
[4] GC Memory: 104,442,028 bytes (array allocated)
[5] GC Memory: 124,450,236 bytes (array allocated)
     GC Memory: 124,450,236 bytes (exited local scope)
     GC Memory: 124,357,588 bytes (after GC collection ran)

All scopes exited:
     GC Memory: 124,365,780 bytes (before GC runs)
     GC Memory: 24,356,996 bytes (after GC collection ran)

To solve your issue:

  1. Make sure you aren't hanging on to any references to the byte[]s. The bytes won't get cleared until all references to the array are gone and it's completely out of scope.
  2. Explicitly call GC.Collect() after you've left the scope of the byte array. Once it's out of scope, the byte[] will clear on its own but you can tell it to run instead of waiting.

Solution 5

It's hard to say for sure without seeing the context that thats used in. Unless you are keeping around references to each outputMessage they will get garbage collected eventually whenever the GC decides to run.

What were you looking at to see that the private bytes kept growing and would never shrink? Also were you only running with the debugger attached or were you running in release?

Do you really need to create a new array every 10 seconds? It might be faster to simply Array.Clear and reuse it.

Share:
36,486
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    I am creating new byte arrays which are not being collected by GC and are living in memory and increasing the private bytes. The code below gets executed every 10 seconds. How do I explicitly clear the variable after I am done with it?

    byte[] outputMessage = new byte[10000];
    //Do some work here
    
  • Admin
    Admin almost 13 years
    I am creating new byte arrays in an event handler somethingclass.onreceivedmessage += onreceivedmessage, where somethingclass lives forever
  • Brian Rasmussen
    Brian Rasmussen almost 13 years
    I agree that the code looks fine as is, so if it isn't collected there must be some other reference. If that is the case setting outputMessage = null and calling GC.Collect will not make a difference.
  • zneak
    zneak almost 13 years
    I've been told that calling GC.Collect() is rarely a good idea. Besides, didn't the OP say that GC runs don't collect the array?
  • Sandeep G B
    Sandeep G B almost 13 years
    There have been reports of memory leaks due to event handlers and the references held because of them. I am not sure if the memory leak you are facing is related to that. You can take a look here stackoverflow.com/questions/1843270/… blogs.msdn.com/b/tess/archive/2006/01/23/… blogs.msdn.com/b/abhinaba/archive/2009/05/05/…
  • Amadan
    Amadan almost 13 years
    @Brian, @zneak: Indeed, I think I did not express myself correctly. The two are separate: clearing his variable would not clear any other reference. I was just illustrating the way how you can explicitly clear any reference even before it gets out of scope, doing things manually. Of course, letting GC decide on its own is a better idea.
  • Admin
    Admin almost 13 years
    The event handler will be unsubscribed only when the windows service is stopped. The service runs 24/7 and it keeps receiving messages continuously.
  • user670800
    user670800 almost 13 years
    how do you find all reference to an object in run time ?
  • user670800
    user670800 almost 13 years
    How about using Array.Resize() to explicitly shrink the array ? That should reduce the memory footprint.
  • Kenneth K.
    Kenneth K. about 10 years
    I don't see how this answers the question. I can implement IDisposable to run MessageBox.Show("Hello World!"), but how does that free up my byte array?
  • Ziaullah Khan
    Ziaullah Khan almost 6 years
    byte[] is a reference type. It is a managed resource. IDisposable is used for unmanaged resources like handles, sockets, raw pointer. Not for managed resources.