我如何明确清除字节

我正在创建新的字节数组,这些数组不是由GC收集的,而是存在于内存中并增加了专用字节。 下面的代码每10秒执行一次。 完成后如何明确清除变量?

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

你怎么知道他们没被收集? 您提供的代码很好,如果您没有任何悬挂引用,它应该有资格收集。

显然,您可以清除引用

 outputMessage = null; 

并且你可以提示GC它应该用它来完成它的工作:

 GC.Collect(); 

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

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

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

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

你是否留下了outputMessage的焦点?
– 如果它是在一个方法中声明的:你离开它还是有一些(强烈的)无限循环并保留在其中?
– 如果它在类对象中声明为全局:您的完整类是否通过引用保留在内存中?

如果没有看到所使用的上下文,很难肯定地说。除非你保留对每个outputMessage的引用,否则每当GC决定运行时,它们最终会被垃圾收集。

您在看什么看到私有字节不断增长并且永远不会缩小? 你也只是附带调试器运行,或者你在发布时运行?

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

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

当托管数组离开作用域时,它会被标记为垃圾回收。 如果数组是值类型,则项的释放很快,但在收集数组之前不会发生。 请记住, 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[]将自行清除,但您可以告诉它运行而不是等待。

此测试用例仅适用于发布模式。 我使用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); }