【问题标题】:Improving performance cost memory in a multithreaded distributed application提高多线程分布式应用程序中的性能成本内存
【发布时间】:2012-02-22 16:10:23
【问题描述】:

我已设法将 Web 应用程序的性能提高到比以前快 10%。有了这个,我注意到内存使用量翻了一番!!!

测试应用程序会:调用 Web 服务,执行一些复杂的业务操作 * [用户数] * [次数]

我检查了我的更改代码,但没有什么可疑的使用更多内存..(我所做的只是删除将 DataSet 序列化为 byte[] 并将其保存在缓存中的代码行) 我在多线程测试中反复检查:

  1. 随着我跳过的代码越来越多(性能提高 - 内存增加
  2. 当我在循环中重复错误代码时(性能很差 - 内存下降)

谁能解释一下为什么????

代码如下:

之前:(循环时间:100% 内存 100%)

            outStream = new MemoryStream();
            new BinaryFormatter().Serialize(outStream, stateData); 
            outStream.Close();
            SessionSettings.StateData_Set(stateId, outStream.ToArray());
            outStream.Dispose();

选项 1 之后:(循环时间:200% 内存 50%)

for (int i = 0; i < 20; i++)
            {
                outStream = new MemoryStream();
                new BinaryFormatter().Serialize(outStream, stateData); 
            }
            outStream.Close();
            SessionSettings.StateData_Set(stateId, outStream.ToArray());
            outStream.Dispose();

选项 2 之后:(循环时间:90% 内存 200%)

                //outStream = new MemoryStream();
                //new BinaryFormatter().Serialize(outStream, stateData); 
            //outStream.Close();
            SessionSettings.StateData_Set(stateId, null);
            //outStream.Dispose();

SessionSettings.StateData_Set 将一个对象放入一个

dictionary<string,dictionary<string, object>>

意思是

<Sessions<DataKey,DataObject>>

在每个循环结束时,内部字典删除条目 并且在每个用户会话结束时,整个内部字典都从外部字典中删除。

【问题讨论】:

  • 请澄清。您删除了序列化的代码,将其替换为保存在缓存中的代码?或者,您删除了序列化和缓存数据的代码?
  • 您能否提供一些见解,您是如何测量内存使用情况的?您是否也考虑了 GC(性能计数器 -> GC 中的时间)?
  • 我删除了序列化的代码和将此序列化值放入缓存的代码。
  • 我还没有使用性能计数器。我在客户端使用秒表来测量平均响应时间,并观察服务器上 w3wp 的任务管理器内存使用情况。

标签: .net multithreading performance memory-management


【解决方案1】:

另一个猜测:如果您的应用程序分配了太多内存(可能是通过频繁序列化),CLR 将更频繁地触发 GC。通过查看性能计数器 -> GC 时间,您会注意到,GC 占用了大量 CPU - 我见过超过 40% 的场景。如果您的数据集很大并且 byte[] 存储最终位于 LOH 上,则尤其如此。

通过限制这些分配,GC 的触发频率将大大降低,从而提高应用程序性能。观察到内存增加的一个原因可能是托管堆现在在健康区域中工作得更多。

为了找到更可靠的解释,请发布一些性能对策:优化之前和优化之后。有趣的是:总体堆大小,GC 所花费的时间。

【讨论】:

  • 您所说的可能有些问题,而内存较高时,CPU 上下浮动 50% 左右,而之前是恒定的 95%。所以也许是 GC 更努力地工作......
  • 我还没有找到官方参考,但是对于 .NET 4.0 来说,如果分配了太多大对象,GC 似乎会以某种压力模式运行。也就是说,它基本上一直在收集,而不仅仅是在托管堆“满”的情况下。这表明永久(第 2 代!)收集的成本要高得多。
  • 我认为你是对的。随着代码变得更好 - 花在 GC 上的时间变得更短并且 gen2 堆大小急剧增长
  • 谢谢。我很高兴你找到了原因。大型 gen2 堆本身并不引人注目。如果它表现得很平静,它不一定会损害性能。但是稳定运行的 GC 肯定会受到伤害。对于重分配场景,我总是尽量不依赖 GC,但很高兴知道,GC 在后面作为 fallback。
【解决方案2】:

由于您没有提供任何代码而只是一个简短的解释,所以它更像是一个谜而不是一个问题。

因此,大概有 10 个用户同时访问缓存数据集。缓存数据集被用户同步锁定和查看(一次一个)。这在多线程测试中表现不佳,但会占用很少的内存。

可能有 10 个用户几乎同时访问了 REPLICATED DATASET(未缓存)。每个用户都有自己的复制数据集副本。如果没有锁定/同步访问和 DATASET 的多个副本,内存会增加,但性能会提高。

【讨论】:

    猜你喜欢
    • 2012-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 2013-08-07
    • 1970-01-01
    • 2011-05-18
    相关资源
    最近更新 更多