int / int64 .net 内存分配

本文关键字:内存 分配 net int64 int | 更新日期: 2023-09-27 18:30:30

我有一个大型应用程序,其内存分配平均约为 30 MB/秒(每个性能监视器字节分配/秒测量)。我正试图大幅削减这一点,而分配的来源并不明显。

为了检测内容,我记录了 CLR/GC 的 ETW 跟踪,并导出了 AllocationTick 事件,该事件记录每次额外分配 100 KB 的时间,以及最近分配的对象类型。这会产生一个大小不错的样品集。三种对象类型占我分配的 70%,但它们有点神秘。

  1. System.Int64 30%
  2. System.Int32 28%
  3. System.Runtime.CompilerServices.CallSite'1[
  4. System.Func'3[System.Runtime.CompilerServices.CallSite,System.Object,System.Object]] 12%

数据集是~70分钟和一百万个事件,所以我对这些数字很有信心。

猜这在某种程度上表明我正在以某种意想不到的方式在堆上创建很多指针?(这是一个 x64 应用程序)

我使用了一些 linq 和 foreach 循环,但这些循环应该只在堆栈上创建增量变量,而不是堆。

我也在TPL/数据流库上运行所有内容,它可以生成这些。

我正在寻找有关可能导致 int32/64 如此多堆分配的原因的任何建议,也许还有一些隔离这些分配的技术(调用堆栈会很棒,但可能性能过高)。

int / int64 .net 内存分配

猜这在某种程度上表明我正在以某种意想不到的方式在堆上创建很多指针?

听起来更有可能的是,你向我提出了很多intlong价值观。

CallSite部分听起来像是你经常使用dynamic(或者在代码的一个非常频繁的部分),这很容易导致比静态类型代码更多的装箱。

我会尝试隔离分配大量对象的代码的特定区域 - 例如,如果您可以只练习特定的代码路径,这将使您更清楚地了解哪些路径生成的垃圾比您预期的要多。看看任何使用dynamic的地方,看看你是否真的需要 - 尽管你不应该觉得你必须以任何方式删除dynamic的所有用途;很可能有一个特殊的"热点"可以进行微观优化。

要考虑的另一件事是这笔分配实际上花费了您多少。你说你正试图大幅削减它——你真的需要吗?如果所有这些对象的生存期都非常短,您可能会发现降低分配率并不能提高性能。您应该测量在垃圾回收中花费的时间,以确定这可能有多有效。