如何显式地清除byte[]
本文关键字:byte 清除 何显式 | 更新日期: 2023-09-27 17:55:02
我正在创建新的字节数组,这些字节数组不被GC收集,并且存在于内存中,并增加了私有字节。下面的代码每10秒执行一次。我如何明确地清除变量后,我完成了它?
byte[] outputMessage = new byte[10000];
//Do some work here
你怎么知道它们没有被收集?您提供的代码很好,如果没有任何悬空引用,它应该符合收集条件。
可以显式地通过
清除引用outputMessage = null;
,你可以提示GC它应该这样做:
GC.Collect();
但是,不能保证您的对象将被收集,并且通常不需要手动干扰GC。
如果你一直在添加一个新的事件处理程序,你会删除任何旧的吗?如果没有,那么他们仍然为你保留参考。
编辑:为清晰起见,并通过OP
当托管数组离开作用域时,它被标记为垃圾收集。如果数组是值类型,则项的释放很快,但直到数组被收集才会发生。请记住,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内存:24,355,488字节(起始内存)
[1] GC内存:44,467,612字节(数组分配)
[2] GC内存:64,681,980 bytes(数组分配)
[3] GC内存:85,493,004字节(数组分配)
[4] GC内存:104,442,028字节(数组分配)
[5] GC内存:124,450,236字节(数组分配)
GC内存:124,450,236字节(退出本地作用域)
所有作用域已退出:
GC内存:124,365,780字节(GC运行前)
GC内存:24,356,996字节(GC收集运行后)
解决您的问题:
- 确保你没有挂在任何引用的
byte[]
s。在对数组的所有引用都被清除之前,字节不会被清除 - 在离开字节数组的作用域后显式调用
GC.Collect()
。一次它在范围之外,byte[]
会自己清除,但你可以
确保没有对数组的引用。检查您没有对另一个变量赋值,该变量将数组保存在内存中。
您是否离开了outputMessage的焦点?
-如果在方法中声明:你是离开它,还是有一些(潜在的)无限循环并留在其中?
-如果在类对象中声明为全局:你的整个类是否通过引用this而保留在内存中?
在没有看到上下文的情况下很难确定。除非您保留对每个outputMessage的引用,否则每当GC决定运行时,它们最终都会被垃圾收集。
是什么让你看到私有字节一直在增长,永远不会缩小?另外,您是只在附带调试器的情况下运行还是在发布版中运行?
你真的需要每10秒创建一个新的数组吗?简单地使用Array可能会更快。清理并重用它。
考虑一下:是否有可能将byte[]封装在实现IDisposable的类中?使用之后,可以通过显式调用dispose()来处理对象。我不确定这是否能引导您找到解决方案,但这将是我的下一次尝试。
这个测试用例只在发布模式下工作。我正在使用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);
}