C#垃圾回收与多线程

MinSi 2013-12-22 03:08:28
问题是这样的,我用C#开发了一套服务器,其中使用了多线程.
本期望能够利用多线程把服务器的所有CPU都利用起来,但经过压力测试后发现,在百人级别时,8核心 CPU占用量可以达到50%左右.
当人数达到1000甚至2000的时候 服务器开始巨卡,查看CPU占用量只有12%-16%(仅一个核心的占用量)

经过无数测试发现,代码中存在new对象操作后,多个线程的确无法完全发挥效率,通过C++代码测试也是如此,
所以我觉得可能new里面操作的是同一个堆,可能有锁. 通过C++实现了线程之间堆的独立,CPU果然占用满了.
但C#却没找到实现类此功能的方法.

还有一个就是GC的垃圾回收,明文写着会挂起所有的线程. 回收完毕再继续.

服务器代码中每tick大概有几百个临时对象的new 当人数上去这些new的量会非常之大,我在手动调用GC垃圾回收的时候做了一个时间统计,最慢的一次居然达到了20秒.

实在解决不了这个问题,来此求助,希望大神能重视能帮忙出主意解决一下!
非常感谢~~~~
...全文
1087 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
showjim 2014-02-27
  • 打赏
  • 举报
回复
另外就是,想办法不要那么多new,试试创建一些对象池,也许可以降低CPU使用
showjim 2014-02-27
  • 打赏
  • 举报
回复
试试修改一下config文件
    <gcServer enabled="true"/>
MinSi 2014-01-13
  • 打赏
  • 举报
回复
引用 12 楼 sp1234 的回复:
你的这个帖子,可以说绝对会误导人。希望你贴出一个足以重现你的问题的测试代码来!
代码贴出来了,求解释下!
石灰石石英石 2014-01-06
  • 打赏
  • 举报
回复
我觉得有可能是内存的问题,内存被挤爆了吧,你说一次GC要20多秒,可能是很多的大对象无法回收,把内存挤爆了,看看你的对象是不是可以回收的,有没有内存陷阱
遗忆灵魂 2014-01-03
  • 打赏
  • 举报
回复
::new 需要包含 #include <string>
遗忆灵魂 2014-01-03
  • 打赏
  • 举报
回复
C++代码测试 #include "stdafx.h" #include <windows.h> DWORD WINAPI _TestThread(LPVOID lpThreadParameter) { while (true) { ; } return 0; } int _tmain(int argc, _TCHAR* argv []) { DWORD xThreadId; for (int i = 0; i < 10; i++) { ::CreateThread(NULL, 0, _TestThread, NULL, 0, &xThreadId); } system("Pause"); return 0; } 一样可以占满CPU使用 class Test { int xNumber; }; DWORD WINAPI _TestThread(LPVOID lpThreadParameter) { while (true) { Test* lpTest = new Test(); } return 0; } 使用new以后,发现CPU一样占不满! 使用此方法后 DWORD WINAPI _TestThread(LPVOID lpThreadParameter) { HANDLE xHeap = ::HeapCreate(0, 0, 1024); while (true) { LPVOID lpNewAddr = ::HeapAlloc(xHeap, 0, sizeof(Test)); if (lpNewAddr) { Test* lpTest = (Test*) lpNewAddr; if (lpTest){ ::new (lpTest) Test(); } } } return 0; } 又可以把CPU占满了,所以我觉得是因为new同一块堆导致了锁!
MinSi 2014-01-03
  • 打赏
  • 举报
回复
.net4之后 GC提供了这个接口. 可以尽可能避免阻塞回收内存. 但并没有实际解决问题 public static void Collect(int generation, GCCollectionMode mode, bool blocking);
MinSi 2014-01-03
  • 打赏
  • 举报
回复
public static void _ThreadStart() { while (true) { Int32 xNumber = 100; String xString = ""; } } 函数内增加局部变量,并不影响CPU占用. public class Test { public Int32 xNumber; } public static void _ThreadStart() { while (true) { Test xTest = new Test(); } } 这样可以很明显看到CPU占用达不到100%了,而且浮动很大!
MinSi 2014-01-03
  • 打赏
  • 举报
回复
用来说明空线程与托管架构多线程可以把CPU占满的例子 using System.Collections.Generic; using System.Threading.Tasks; using System.Threading; using System; namespace ThreadTest { static class Program { public static void _ThreadStart() { while(true) { ; } } [STAThread] static void Main() { for (Int32 i = 0; i < 10; i++) { Thread xThread = new Thread(_ThreadStart); xThread.Start(); } while (true) { Thread.Sleep(1000000); } } } }
Frog1228 2014-01-02
  • 打赏
  • 举报
回复
引用 13 楼 mjjackey 的回复:
[quote=引用 8 楼 yangyy9611 的回复:] 听起来像是高并发下new对象时导致的。一种解决方式就是看看你能不能够重用以前分配的对象。而不是每次都new。一来托管程序的new本身就是很慢的,比C++可能要慢上百倍。另一个就是频繁的new,垃圾回收到后面可能还会产生内存碎片的问题。
“一种解决方式就是看看你能不能够重用以前分配的对象。”用内存池。 手动调用GC垃圾回收时间是会很慢的。[/quote] 可能你的问题不是在new的部分,还是高并发的问题。
sinodzh 2013-12-31
  • 打赏
  • 举报
回复
跟new有什么关系。跟堆栈有什么关系。数据是数据。操作是操作。
Frog1228 2013-12-31
  • 打赏
  • 举报
回复
引用 8 楼 yangyy9611 的回复:
听起来像是高并发下new对象时导致的。一种解决方式就是看看你能不能够重用以前分配的对象。而不是每次都new。一来托管程序的new本身就是很慢的,比C++可能要慢上百倍。另一个就是频繁的new,垃圾回收到后面可能还会产生内存碎片的问题。
“一种解决方式就是看看你能不能够重用以前分配的对象。”用内存池。 手动调用GC垃圾回收时间是会很慢的。
  • 打赏
  • 举报
回复
你的这个帖子,可以说绝对会误导人。希望你贴出一个足以重现你的问题的测试代码来!
  • 打赏
  • 举报
回复
引用 楼主 MinSi 的回复:
经过无数测试发现,代码中存在new对象操作后,多个线程的确无法完全发挥效率,
看不懂你什么意思。能不能写个例子重现你的问题? 如果没事就总是new,这又何必?但是谁知道你怎么new的呢?
zouyongp 2013-12-26
  • 打赏
  • 举报
回复
好厉害的样子
Ohyes陈陈 2013-12-24
  • 打赏
  • 举报
回复
yangyy9611 2013-12-24
  • 打赏
  • 举报
回复
听起来像是高并发下new对象时导致的。一种解决方式就是看看你能不能够重用以前分配的对象。而不是每次都new。一来托管程序的new本身就是很慢的,比C++可能要慢上百倍。另一个就是频繁的new,垃圾回收到后面可能还会产生内存碎片的问题。
by_封爱 2013-12-23
  • 打赏
  • 举报
回复
1W以下的 或者用异步
by_封爱 2013-12-23
  • 打赏
  • 举报
回复
高并发 就用线程池吧...
rtdb 2013-12-23
  • 打赏
  • 举报
回复
线程开太多了, 若是再有锁或共享资源(例如数据库)的话,就肯定跑不好了
加载更多回复(4)

17,740

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 .NET Framework
社区管理员
  • .NET Framework社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧