dotnet C# - 为什么 GC 不释放内存?
dotnet C# - Why doesn't the GC free memory?
我想问一下 .net 垃圾收集器在这种情况下是如何工作的。
我有一个静态函数,我在其中一遍又一遍地分配字节数组。我正在将字节数组引用插入到列表中。对字节数组或列表的引用未传递到此函数之外。
public static void StressMem(TimeSpan duration)
{
var bgnTm = DateTime.Now;
var data = new List<byte[]>();
while (true)
{
var arr = new byte[1024];
data.Add(arr);
var difTm = DateTime.Now - bgnTm;
if (difTm > duration) break;
}
}
我原以为当这个函数完成后内存会被释放(一段时间后)。但这不会发生在我身上。为什么会这样?
网络 5.0.302
原则上,GC 可以随时 运行 自由,或者根本不这样做。在实践中,我不希望它 运行 除非你真的想分配一些东西。所以在 StressMem
returns 之后你可能看不到任何 GC,除非你做更多需要内存的工作。如果你 运行 StressMem
在一个循环中,我会期望频繁的 GC。
请注意,这并不一定意味着进程的内存使用量会减少。如果物理内存 运行 不足,垃圾收集器可能 return 内存到 OS,但是你有空闲内存吗,为什么不使用它?
如果您正在调查您的应用程序如何使用内存,我建议您使用内存 and/or 性能分析器。他们应该揭示您为 GC 使用了多少时间、您将内存用于什么、分配了多少等。
尝试 运行使用此代码:
void Main()
{
GC.Collect();
long x = GC.GetTotalMemory(false);
StressMem(TimeSpan.FromMilliseconds(100.0));
long y = GC.GetTotalMemory(false);
GC.Collect();
long z = GC.GetTotalMemory(false);
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(z);
}
public static void StressMem(TimeSpan duration)
{
var bgnTm = DateTime.Now;
var data = new List<byte[]>();
while (true)
{
var arr = new byte[1024];
data.Add(arr);
var difTm = DateTime.Now - bgnTm;
if (difTm > duration) break;
}
}
这就是您使用一些检查内存的代码的确切方法。
我得到:
2278192
59759468
2278640
它显然是在分配内存和 GC,当被迫 运行 时,会收集它。
当内存有压力时,GC 仅 运行s。它不是基于“某个时间”。
如果我没理解错的话,GC是不释放内存的,除非有原因。比如我做一个程序,占用了一些内存,然后什么都不做,那么进程就会占用内存,很可能不会再释放了(除非直接调用GC.Collect()
)。我在一个小例子上试过了(见下文)。
public static void StressMem(TimeSpan duration)
{
var bgnTm = DateTime.Now;
var data = new List<byte[]>();
while (true)
{
var arr = new byte[1024];
data.Add(arr);
var difTm = DateTime.Now - bgnTm;
if (difTm > duration) break;
}
}
static void Main(string[] args)
{
var mem = GC.GetTotalMemory(false);
Console.WriteLine($"{DateTime.Now} [Begin] {mem}");
StressMem(TimeSpan.FromSeconds(5));
mem = GC.GetTotalMemory(false);
Console.WriteLine($"{DateTime.Now} [StressMem] {mem}");
var dt = DateTime.Now;
var lastPrint = dt;
while (true)
{
var now = DateTime.Now;
if (now - lastPrint > TimeSpan.FromSeconds(15))
{
lastPrint = now;
mem = GC.GetTotalMemory(false);
Console.WriteLine($"{DateTime.Now} {mem}");
}
if (now - dt > TimeSpan.FromMinutes(15)) break;
}
}
我想问一下 .net 垃圾收集器在这种情况下是如何工作的。
我有一个静态函数,我在其中一遍又一遍地分配字节数组。我正在将字节数组引用插入到列表中。对字节数组或列表的引用未传递到此函数之外。
public static void StressMem(TimeSpan duration)
{
var bgnTm = DateTime.Now;
var data = new List<byte[]>();
while (true)
{
var arr = new byte[1024];
data.Add(arr);
var difTm = DateTime.Now - bgnTm;
if (difTm > duration) break;
}
}
我原以为当这个函数完成后内存会被释放(一段时间后)。但这不会发生在我身上。为什么会这样?
网络 5.0.302
原则上,GC 可以随时 运行 自由,或者根本不这样做。在实践中,我不希望它 运行 除非你真的想分配一些东西。所以在 StressMem
returns 之后你可能看不到任何 GC,除非你做更多需要内存的工作。如果你 运行 StressMem
在一个循环中,我会期望频繁的 GC。
请注意,这并不一定意味着进程的内存使用量会减少。如果物理内存 运行 不足,垃圾收集器可能 return 内存到 OS,但是你有空闲内存吗,为什么不使用它?
如果您正在调查您的应用程序如何使用内存,我建议您使用内存 and/or 性能分析器。他们应该揭示您为 GC 使用了多少时间、您将内存用于什么、分配了多少等。
尝试 运行使用此代码:
void Main()
{
GC.Collect();
long x = GC.GetTotalMemory(false);
StressMem(TimeSpan.FromMilliseconds(100.0));
long y = GC.GetTotalMemory(false);
GC.Collect();
long z = GC.GetTotalMemory(false);
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(z);
}
public static void StressMem(TimeSpan duration)
{
var bgnTm = DateTime.Now;
var data = new List<byte[]>();
while (true)
{
var arr = new byte[1024];
data.Add(arr);
var difTm = DateTime.Now - bgnTm;
if (difTm > duration) break;
}
}
这就是您使用一些检查内存的代码的确切方法。
我得到:
2278192
59759468
2278640
它显然是在分配内存和 GC,当被迫 运行 时,会收集它。
当内存有压力时,GC 仅 运行s。它不是基于“某个时间”。
如果我没理解错的话,GC是不释放内存的,除非有原因。比如我做一个程序,占用了一些内存,然后什么都不做,那么进程就会占用内存,很可能不会再释放了(除非直接调用GC.Collect()
)。我在一个小例子上试过了(见下文)。
public static void StressMem(TimeSpan duration)
{
var bgnTm = DateTime.Now;
var data = new List<byte[]>();
while (true)
{
var arr = new byte[1024];
data.Add(arr);
var difTm = DateTime.Now - bgnTm;
if (difTm > duration) break;
}
}
static void Main(string[] args)
{
var mem = GC.GetTotalMemory(false);
Console.WriteLine($"{DateTime.Now} [Begin] {mem}");
StressMem(TimeSpan.FromSeconds(5));
mem = GC.GetTotalMemory(false);
Console.WriteLine($"{DateTime.Now} [StressMem] {mem}");
var dt = DateTime.Now;
var lastPrint = dt;
while (true)
{
var now = DateTime.Now;
if (now - lastPrint > TimeSpan.FromSeconds(15))
{
lastPrint = now;
mem = GC.GetTotalMemory(false);
Console.WriteLine($"{DateTime.Now} {mem}");
}
if (now - dt > TimeSpan.FromMinutes(15)) break;
}
}