最近写了一个WinFrom程序。此程序侦听TCP端口,接受消息处理,然后再把处理后的消息,利用线程池通过WebService发送出去(即一进一出)。

在程序编写完成后,进行压力测试。用Fiddler提交1万请求。

                ThreadPool.QueueUserWorkItem((o) =>
{
try
{
APPService.AddLog(o as MDMPortalWCF.LogInfo);//发送此Log时,是提交WebService请求的。
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
} },log);

 使用procexp.exe查看,随着TCP请求的增多,2代GCHeap不断增大。是明显的内存泄漏线索。

使用WinDbg分析,GC2明显大,线程正在忙。发现很多String(LogInfo中的属性)被System.Threading.ThreadPoolWorkQueue.QueueSegment引用。正是内存高的原因。

使用Fiddler查看,发现出乎意料的行为,1万个TCP接受完成后,Log却没有发送完。而是持续之后很久,一直发送,直到几分钟后才发送完成。

    此行为表明,ThreadPool倾向于少数线程排队任务,不倾向于开很多线程迅速完成任务。

当发送日志的任务在ThreadPool的队列排队时,LogInfo不会被GC回收,而是被QueueSegment持有。待ThreadPool执行完成后,QueueSegment不再引用任务对象,故内存被回收。

后来想想,ThreadPool.QueueUserWorkItem(WaitCallback callBack, object state)中的state对象,在被执行前,将一直被引用,这是合情合理的。但由于ThreadPool的排队性质,导致内存释放也是缓慢的,往往是人们想不到的。在此记录,以示后人。

2018-03-23  

在网上读到一篇文章(http://www.albahari.com/threading/#_Optimizing_the_Thread_Pool)说的非常详细。更好的解释了如上的现象。SetMinThreads是一种高级优化线程池的技术。线程池策略是经济型的,即尽量节省线程新建,这是为了防止多个短生命期任务造成内存突然膨胀。但当入队的任务,超过半秒执行时间,线程池才开始每半秒新增一个Thread。当然,这也造成了一些问题,比如多个访问互联网的线程,我们希望同时一起访问。这时需要设置ThreadPool.SetMinThreads(100,100),这条语句,告诉线程池管理器,在前100个线程内,不要等待半秒,任务来了,立即创建线程。原文如下:

How Does the Minimum Thread Count Work?

Increasing the thread pool’s minimum thread count to x doesn’t actually force x threads to be created right away — threads are created only on demand. Rather, it instructs the pool manager to create up to x threads the instant they are required. The question, then, is why would the thread pool otherwise delay in creating a thread when it’s needed?

The answer is to prevent a brief burst of short-lived activity from causing a full allocation of threads, suddenly swelling an application’s memory footprint. To illustrate, consider a quad-core computer running a client application that enqueues 40 tasks at once. If each task performs a 10 ms calculation, the whole thing will be over in 100 ms, assuming the work is divided among the four cores. Ideally, we’d want the 40 tasks to run on exactly four threads:

  • Any less and we’d not be making maximum use of all four cores.
  • Any more and we’d be wasting memory and CPU time creating unnecessary threads.

And this is exactly how the thread pool works. Matching the thread count to the core count allows a program to retain a small memory footprint without hurting performance — as long as the threads are efficiently used (which in this case they are).

But now suppose that instead of working for 10 ms, each task queries the Internet, waiting half a second for a response while the local CPU is idle. The pool manager’s thread-economy strategy breaks down; it would now do better to create more threads, so all the Internet queries could happen simultaneously.

Fortunately, the pool manager has a backup plan. If its queue remains stationary for more than half a second, it responds by creating more threads — one every half-second — up to the capacity of the thread pool.

The half-second delay is a two-edged sword. On the one hand, it means that a one-off burst of brief activity doesn’t make a program suddenly consume an extra unnecessary 40 MB (or more) of memory. On the other hand, it can needlessly delay things when a pooled thread blocks, such as when querying a database or calling WebClient.DownloadFile. For this reason, you can tell the pool manager not to delay in the allocation of the first x threads, by calling SetMinThreads, for instance:

ThreadPool.SetMinThreads (50, 50);

(The second value indicates how many threads to assign to I/O completion ports, which are used by the APM, described in Chapter 23 of C# 4.0 in a Nutshell.)

The default value is one thread per core.

.Net线程池ThreadPool导致内存高的问题分析的更多相关文章

  1. 线程池ThreadPool的初探

    一.线程池的适用范围 在日常使用多线程开发的时候,一般都构造一个Thread示例,然后调用Start使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...

  2. C#多线程学习 之 线程池[ThreadPool](转)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  3. 多线程Thread,线程池ThreadPool

    首先我们先增加一个公用方法DoSomethingLong(string name),这个方法下面的举例中都有可能用到 #region Private Method /// <summary> ...

  4. C# 线程池ThreadPool的用法简析

    https://blog.csdn.net/smooth_tailor/article/details/52460566 什么是线程池?为什么要用线程池?怎么用线程池? 1. 什么是线程池? .NET ...

  5. C#多线程学习 之 线程池[ThreadPool]

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  6. 线程池ThreadPool实战

    线程池ThreadPool 线程池概念 常用线程池和方法 1.测试线程类 2.newFixedThreadPool固定线程池 3.newSingleThreadExecutor单线程池 4.newCa ...

  7. [转]C#多线程学习 之 线程池[ThreadPool]

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  8. 【C# 线程】线程池 ThreadPool

    Overview    如今的应用程序越来越复杂,我们常常需要使用<异步编程:线程概述及使用>中提到的多线程技术来提高应用程序的响应速度.这时我们频繁的创建和销毁线程来让应用程序快速响应操 ...

  9. 高效线程池(threadpool)的实现

    高效线程池(threadpool)的实现 Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线 ...

随机推荐

  1. pl/sql小技巧

    更正方法: 然后把Automatic statistics的勾选去掉,点击apply即可

  2. GitHub中watch、star、fork的作用

    star 的作用是收藏,目的是方便以后查找. watch 的作用是关注,目的是等作者更新的时候,你可以收到通知. fork 的作用是参与,目的是你增加新的内容,然后 Pull Request,把你的修 ...

  3. C# 多线程小试牛刀

    前言 昨天在上班时浏览博问,发现了一个问题,虽然自己在 C# 多线程上没有怎么尝试过,看了几遍 CLR 中关于 线程的概念和讲解(后面三章).也想拿来实践实践.问题定义是这样的: 对于多线程不是很懂, ...

  4. CodeForces - 813C The Tag Game (树的dfs遍历)

    [传送门]http://codeforces.com/problemset/problem/813/C [题目大意]两个人玩游戏,一个人跑一个人追,轮流决策,可以走也可以不走.给你一棵树,想要从某个结 ...

  5. java基础之IO流(一)字节流

    java基础之IO流(一)之字节流 IO流体系太大,涉及到的各种流对象,我觉得很有必要总结一下. 那什么是IO流,IO代表Input.Output,而流就是原始数据源与目标媒介的数据传输的一种抽象.典 ...

  6. Windows 10安装IntelliJ IDEA时快捷键冲突设置

    Windows的快捷键的非常多,而且个性化软件获得这些权限的也很多,所以没有最终的方法,只能不断的发现和尝试. 下面是收集的一些教程,或许能在这里找到灵感: 切记:不建议优先修改IDEA的快捷键,应该 ...

  7. go语言学习之路 一:开发环境配置

    1. 安装go 1)下载地址:http://www.golangtc.com/download,下载后直接双击msi文件安装,默认安装在c:\go 2)安装完成后默认会在环境变量 Path 后添加 G ...

  8. 使用SourceTree 来管理 Gitcafe 的Pages 发布Blog!

    有个好爹的 SourceTree 是来自 JIRA 的娘家 Bitbucket 的新东家 ATLASSIAN.com 一家成功的,对敏捷软件工程拥有全栈式支持的商业公司, 所推出的 MAC 专用, S ...

  9. Oracle EBS - 工单状态

    Job status update 1. Job的几种状态 unreleased --未核发 released--已核发 complete --完成 complete no charges--完成不计 ...

  10. 【JSON注解】注解@JsonIgnoreProperties和@JsonIgnore的另一个使用情况

    之前关于这两个注解,是用在JSON循环引用的情况上,那么现在关于这两个注解,还可以使用在另外一种情况上 即: 一般标记在属性或者方法上,返回的json数据即不包含该属性 关于这种情况在什么时候会遇到呢 ...