1

实际上,我开发了一个基于 tcp 的网络服务器,它可以进行大量的读写操作,并且其业务逻辑使用的 CPU 小于零,它充当两个端点之间的桥梁。网络服务器是为 .NET 4.5 开发的,它使用:

  • IOCP (Socket.xxxAsync)
  • 预先分配的 SocketAsyncEventArgs 的缓冲池(用于 SendAsync 和 ReadAsync)
  • 预分配字节[]的缓冲池(仅用于读取)
  • System.Collections.Concurrent
  • 小于零锁(嗯,实际上有一个:))
  • 其他一些东西

我的担忧与垃圾收集有关,事实上,据我所知,虽然我避免内存碎片预分配我需要的所有缓冲区,但垃圾收集器检查它们是否必须被收集,因为它们没有分配在大堆内.

会更好,而不是分配 10.000 字节 [8192] 会更好地分配一个大字节 [81920000] 并使用 ArraySegment 来使用切片?

谢谢你。

更新

我切换到服务器模式垃圾收集,似乎我的系统比以前工作得更好(实际上我能够在同一台机器上处理多达 4GiB 的流量和 5000 个客户端,这意味着 10000 个套接字)。简而言之,我将开始在更多机器上测试架构。

4

3 回答 3

0

您需要注意如何分解数据以进行发送和接收。接收数据时,尽量保持任何缓冲区低于 LOH 的最小值,即 <80Kb。发送也一样。

另一种方法是创建一个固定大小的缓冲区池,以便根据需要使用和回收。这避免了分配的不断创建和破坏,避免了任何内存碎片问题。

与大多数问题一样,最终选择取决于最终解决方案的最佳选择。仅使用小缓冲区可以更容易地避免碎片,但这也会带来相关的性能成本。

于 2013-05-16T11:52:43.167 回答
0

客户端-服务器应用程序在简单的情况下意味着N个客户端和1 个服务器。每个客户端请求都应是独立的,并且独立于其他客户端的请求。这允许您使用N个线程来支持N个并发用户。

现在,线程不使用共享资源是很重要的。他们可以,但这是对性能的打击。即使您使用乐观(无锁)并发模型,这并不意味着线程不会竞争共享资源。

现在,如果每个线程有一个单独的缓冲区,则每个线程都使用自己的内存,并且不同的并发线程之间不存在竞争。如果你有很多用户,这会增加内存碎片和 GC 花费的 CPU 时间。

如果您使用一个大但共享的缓冲区,您将增加尝试访问不同线程的共享缓冲区所花费的时间。而且你也会减少 GC 做收集工作所花费的时间。


就个人而言,我只会为每个线程使用 1 个小缓冲区。这有好处:

  • 简单模型
  • 编写代码更少,无需同步
  • 您的 CPU 级别很小,因此无需进行性能优化
  • 这个模型更容易水平扩展:添加另一个服务器和一个负载均衡器。它开箱即用。
于 2013-05-16T12:10:55.170 回答
0

我在开发基于SocketAsyncEventArgs.

问题是当您使用缓冲区 ( byte[])时,它会被固定。所以实际上GC对此无能为力。

我个人写了这个类(不完全是这个):

class Buffer
{
    const int BUFFER_SIZE = 8 * 1024;

    public Buffer()
    {
        InUse = false;
        Bytes = new byte[BUFFER_SIZE];
    }

    public bool InUse { get; set; }
    public byte[] Bytes { get; private set; }
}

还有另一个名为的类BufferPool,它有List<Buffer>一个缓冲区池(在我的情况下,检测死连接和释放它们的池等的逻辑非常复杂,所以我跳过了内部)。

这样,您可以重用分配的字节数组作为新操作的缓冲区。

我以这种方式实现了它,因为我无法限制最大连接数。如果您可以将连接数限制为特定的最大值,那么此 codeproject 文章会有所帮助。

注意:我忘了说在这种情况下没有办法回收分配的内存。

于 2013-05-16T12:07:48.660 回答