我如何显式清除字节[]

发布于 2024-11-05 01:05:18 字数 166 浏览 1 评论 0原文

我正在创建新的字节数组,这些数组不被 GC 收集,并且存在于内存中并增加私有字节。下面的代码每 10 秒执行一次。使用完变量后如何显式清除该变量?

byte[] outputMessage = new byte[10000];
//Do some work here

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

相守太难 2024-11-12 01:05:18

你怎么知道它们没有被收集?您提供的代码很好,如果您没有任何悬而未决的引用,它应该可以被收集。

明确地,您可以通过以下方式清除引用

outputMessage = null;

,并且可以提示 GC 它应该这样做:

GC.Collect();

但是,不能保证您的对象将被收集,并且通常不需要手动弄乱 GC。

如果您一直添加新的事件处理程序,是否会删除旧的事件处理程序?如果没有,那么他们仍然为您保留参考。

编辑:为了清楚起见,以及OP的新信息

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

避讳 2024-11-12 01:05:18

当托管数组离开作用域时,它会被标记为垃圾回收。如果数组是值类型,则项目的释放很快,但直到数组被收集后才会发生。请记住,byte 是值类型,但 byte[] 是引用类型。

这是一个快速示例,说明了:

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)));
}

输出看起来像这样(确切的结果会有所不同):

当数组保留在方法的范围内时:

    GC内存:24,576,232字节(起始内存)

[1] GC内存:45,002,324字节(本地数组分配)

[2] GC内存:44,845,548字节(本地数组分配)

[3] GC内存:64,574,296字节(本地数组分配)

[4] GC内存:64,959,472字节(本地数组分配)

[5] GC内存:44,675,340字节(本地数组分配)

    GC 内存:44,675,340 字节(退出本地范围)

    GC 内存:24,347,296 字节(GC 收集运行后)

当数组超出方法的范围时:

    GC内存:24,355,488字节(起始内存)

[1] GC 内存:44,467,612 字节(已分配数组)

[2] GC 内存:64,681,980 字节(已分配数组)

[3] GC 内存:85,493,004 字节(已分配数组)

[4] GC 内存:104,442,028 字节(已分配数组)

[5] GC 内存:124,450,236 字节(已分配数组)

    GC内存:124,450,236字节(退出本地范围)

    GC 内存:124,357,588 字节(GC 收集运行后)

所有范围均已退出:

    GC 内存:124,365,780 字节(GC 运行之前)

   GC 内存:24,356,996 字节(GC 收集运行后)

要解决您的问题:

  1. 确保您没有保留对 byte[]s.
    在对数组的所有引用都被清除之前,字节不会被清除
    消失了,完全超出了范围。
  2. 离开字节数组的范围后显式调用 GC.Collect()。一次
    它超出了范围,byte[] 将自行清除,但您可以
    告诉它运行而不是等待。

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.
起风了 2024-11-12 01:05:18

确保您没有对数组的引用。检查是否没有对另一个将数组保留在内存中的变量进行赋值。

您是否离开了输出消息的焦点?
- 如果它是在方法内部声明的:您是离开它还是有一些(意图)无限循环并保留在其中?
- 如果它在类对象内声明为全局的:您的完整类是否通过对此的引用保留在内存中?

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?

雨的味道风的声音 2024-11-12 01:05:18

在没有看到所使用的上下文的情况下很难确定。除非您保留对每个outputMessage的引用,否则每当GC决定运行时它们最终都会被垃圾收集。

您通过什么看到私有字节不断增长并且永远不会缩小?另外,您是仅在附加调试器的情况下运行还是在发布版本中运行?

你真的需要每 10 秒创建一个新数组吗?简单地使用 Array.Clear 并重用它可能会更快。

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.

笔落惊风雨 2024-11-12 01:05:18

考虑一下:是否可以将 byte[] 封装在实现 IDisposable 的类中?使用后,您可以通过显式调用 Dispose() 来处置您的对象。我不确定这是否能引导您找到解决方案,但这将是我的下一次尝试。

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.

锦上情书 2024-11-12 01:05:18

该测试用例仅适用于发布模式。
我正在使用 guid 类创建一个数组(这很简单)。它将有 16 个元素。

[TestMethod]
public void ByteArrayReleasesMemoryWhenTheyGoOutOfScope()
{
    // *** WORKS ONLY IN RELEASE MODE ***
    // arrange
    var weakRef = new WeakReference(null);

    // easy way to generate byte array
    var byteArray = Guid.NewGuid().ToByteArray();
    weakRef.Target = byteArray;

    // act
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    // assert
    Assert.IsFalse(weakRef.IsAlive);
}

This test case only works in release mode.
I am creating an array using a guid class (it's easy). It would have 16 elements.

[TestMethod]
public void ByteArrayReleasesMemoryWhenTheyGoOutOfScope()
{
    // *** WORKS ONLY IN RELEASE MODE ***
    // arrange
    var weakRef = new WeakReference(null);

    // easy way to generate byte array
    var byteArray = Guid.NewGuid().ToByteArray();
    weakRef.Target = byteArray;

    // act
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    // assert
    Assert.IsFalse(weakRef.IsAlive);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文