C#线程不释放内存
Posted
技术标签:
【中文标题】C#线程不释放内存【英文标题】:C# Thread not releasing memory 【发布时间】:2011-09-13 22:54:52 【问题描述】:我有一个用 C#.Net 编写的 Windows 服务。服务启动后,我生成了一个新线程,如下所示
new Thread(new ThreadStart(Function1)).Start();
此线程无限循环并执行我的服务预期的职责。每天一次,我需要同时执行一个不同的操作,我的线程为此生成第二个线程,如下所示
new Thread(new ThreadStart(Function2)).Start();
第二个线程执行一个非常简单的功能。它使用 FileReadAllLines 读取文本文件的所有行,快速处理这些信息并退出。
我的问题是读取文件的第二个线程使用的内存没有被收集。我让我的服务运行了 3 个小时,希望能调用 GC,但什么也没发生,任务管理器仍然显示我的服务正在使用 150mb 的内存。读取和处理文本文件的函数是一个非常简单的函数,我确信没有对包含文本的字符串数组的隐藏引用。有人可以解释为什么会这样吗?是否有可能由另一个生成的线程生成的线程无法自行清理?
谢谢
【问题讨论】:
我认为实际查看在第二个线程上运行的代码会有所帮助。 您的第二个线程是否正确处理了用于读取文件的流? 你怎么知道你有泄漏。众所周知,从任务管理器中读取数字很容易出错。除非您真正了解 Windows 内存管理和 .net 内存管理的工作原理,否则您会误解这些数字。 这个问题很难理解,但我建议你使用 ThreadPool 而不是手动创建新线程或使用 System.Threading.Timer - WinServices 中通常会安排一些后台工作。 “使用 150 兆内存”字面意思是毫无意义。是您正在使用地址空间的“内存”吗?如果是,有多少是共享的?在未共享的工作集中,分配了多少,提交了多少,有多少在物理内存而不是页面文件中?在您知道所有这些问题的答案之前,分析内存使用情况是没有意义的。但坦率地说,150 兆是很小,你可能不应该担心它。你能解释一下你为什么关心吗?另外,不要使用任务管理器。使用内存分析器来分析内存使用情况,这就是它的用途。 【参考方案1】:相信垃圾收集器,不要担心。 150 兆是什么。您甚至没有在其中测量文件的大小;其中大部分将是代码。
如果您关心内存的去向,请先了解内存在现代操作系统中的工作原理。您需要了解虚拟内存和物理内存之间的区别、已提交内存和已分配内存之间的区别以及所有这些,然后才能开始抛出诸如“150 兆已分配内存”之类的数字。请记住,您在 32 位进程中有 2000 兆的虚拟地址空间;我不认为 150 兆的过程无论如何都很大。
正如 Jon 所说,您需要关注的是私有字节的缓慢稳定增长。如果这没有发生,那么您就没有内存泄漏。让垃圾收集器完成它的工作,不要担心。
如果您 仍然担心它,请不要使用任务管理器。获取内存分析器并学习如何使用它。任务管理器用于通过从 30000 英尺的高度俯视进程来检查进程。您需要使用显微镜而不是望远镜来分析进程如何释放单个文件的字节。
【讨论】:
谢谢。让我微笑的是显微镜,而不是望远镜 可能最好的工具是 Process Explorer (technet.microsoft.com/en-us/sysinternals/bb896653)。它有一堆 .NET 特定信息 Process Explorer 非常有用,但我更倾向于从 CLR Profiler 开始(下载1.1、2.0、4.0)【参考方案2】:如果您使用 Windows 任务管理器来尝试计算所使用的内存,它可能会欺骗您。据我所知,CLR 使用的内存通常不会返回给操作系统......所以你可能仍然会看到一个高工作集,即使大部分内存仍然可以在其中重用过程。
如果您让服务运行一周,您会看到内存使用量在一周内稳步攀升,还是仅在第一天增加,然后趋于平稳?如果是这样,您肯定认为这是一个问题吗?如果是这样,您可能需要将第二个任务放在单独的进程中。
【讨论】:
这可能是解决方案。有没有办法强制将内存返回给操作系统,或者如果另一个应用程序需要此内存,这是否会自动发生? @newidforu:你在操作系统中有大量的虚拟内存......虽然我相信 GC 可能会响应全球压力。我承认我不太清楚究竟在记忆方面会发生什么。理想情况下,您不希望交换“浪费”的内存,但这可能最终会发生......以上是关于C#线程不释放内存的主要内容,如果未能解决你的问题,请参考以下文章