- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在通过内存分析器运行我的应用程序以检查是否有泄漏。事情似乎有点好,但我得到了很多这些 OverlappedData,它们似乎在终结器队列中徘徊,几乎什么都不做。它们是重叠 IO 的结果,已通过关闭连接两端的底层 NetworkStream
取消。
网络流本身被释放。任何地方都没有 NetworkStream
的实时实例。
通常,它们 Root 于称为 OverlappedDataCacheLine
的东西。我做的第一件事就是在回调中调用 EndRead
,所以没有调用 BeginRead
应该没有相应的 EndRead
。
这是一个非常典型的外观,表明谁将它从工具中取出
最后它确实得到了 GC,但它需要永远 - 当我开始大约一千个流时,大约需要半小时才能杀死所有东西,将它们放入异步调用中到 BeginRead
并在大约一分钟后关闭它们。
此程序在某种程度上针对端口 80 上的网络服务器重现了该问题。任何网络服务器都可以。
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
class Program
{
static void Main(string[] args)
{
var clients = new List<TcpClient>();
for (int i = 0; i < 1000; ++i) {
var client = new TcpClient();
clients.Add(client);
client.BeginConnect("localhost", 80, connectResult =>
{
client.EndConnect(connectResult);
var stream = client.GetStream();
stream.BeginRead(new byte[1000], 0, 1000, result =>
{
try
{
stream.EndRead(result);
Console.WriteLine("Finished (should not happen)");
}
catch
{
// Expect to find an IO exception here
Console.WriteLine("Faulted");
}
}, stream);
}, client);
}
Thread.Sleep(10000); // Make sure everything has time to connect
foreach (var tcpClient in clients)
{
tcpClient.GetStream().Close();
tcpClient.Close();
}
clients.Clear(); // Make sure the entire list can be GC'd
Thread.Sleep(Timeout.Infinite); // Wait forever. See in profiler to see the overlapped IO take forever to go away
}
}
诚然,这个程序不会花很长时间来清除上千个OverlappedData
,因为它比实际应用程序小得多,但它确实需要一段时间才能完成它的工作。当我运行我的真实应用程序而不是这个测试应用程序时,我收到了终结器卡住的警告。它在我的应用程序中没有做太多事情,只是尝试关闭可能尚未关闭的所有内容,并确保没有任何引用保留在任何地方。
如果我在客户端上调用 Dispose()
或 Close()
似乎根本无关紧要,它是流。结果是一样的。
关于为什么会发生这种情况以及如何避免这种情况的任何线索?是不是 CLR 对我很聪明,并保持这些固定的内存块完好无损,以便为新调用做准备?为什么终结器的完成速度如此之慢?
更新 在通过将一杯水放在 F5 键上并喝了一些咖啡进行了一些非常愚蠢的负载测试之后,似乎某些东西在收集这些东西的压力下触发了更完整的 GC。所以实际上似乎不是一个真正的问题,但仍然很高兴知道这里到底发生了什么,为什么收集这个对象比其他对象慢得多,如果这可能是一个稍后会出现内存碎片等问题。
最佳答案
好的,现在似乎很清楚发生了什么。垃圾收集只会在您分配内存时发生。它需要至少 2 兆字节的分配,这是第 0 代 GC 堆的典型初始大小才能触发 GC。换句话说,一个什么都不做的程序永远不会运行 GC,您会在内存分析器中看到堆中长时间未被收集的任何对象。
这很好地解释了您所描述的内容。终止所有连接后,您的程序就不必再做任何事情了。因此不会分配太多内存,因此不会触发收集。如果您的探查器不显示集合,那么您可以使用 Perfmon.exe 查看它们。否则这根本不是问题,只是垃圾收集器工作方式的副作用。
只有当您有明确证据表明程序存在资源消耗失控问题时,才需要担心泄漏。
关于c# - 为什么 GC System.Threading.OverlappedData 需要这么长时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12296752/
我一直在慢慢耗尽内存。我已经使用 WinDbg 来查看内存转储,这是它的样子: 000007f975ee0630 557377 41027736 System.Object[] 00000
我正在通过内存分析器运行我的应用程序以检查是否有泄漏。事情似乎有点好,但我得到了很多这些 OverlappedData,它们似乎在终结器队列中徘徊,几乎什么都不做。它们是重叠 IO 的结果,已通过关闭
我是一名优秀的程序员,十分优秀!