我有一个大型应用程序,其内存分配平均约为 30 MB/秒(根据性能监视器分配的字节数/秒测量值)。我正试图大幅减少它,分配的来源并不明显。
为了检测,我记录了 CLR/GC 的 ETW 跟踪,并导出了 AllocationTick 事件,每次分配额外的 100 KB 时都会记录该事件,以及最近分配的对象类型。这会产生一个大小合适的样本集。三种对象类型占我分配的 70%,但它们有点神秘。
- System.Int64 30%
- System.Int32 28%
- System.Runtime.CompilerServices.CallSite'1[System.Func'3[System.Runtime.CompilerServices.CallSite,System.Object,System.Object]] 12%
数据集大约有 70 分钟和一百万个事件,所以我对这些数字很有信心。
我猜这在某种程度上表明我正在以某种意想不到的方式在堆上创建大量指针? (这是一个 x64 应用程序)
我使用了一些 linq 和 foreach 循环,但这些应该只在堆栈上创建增量变量,而不是在堆上。
我也在 TPL/Dataflow 库之上运行所有内容,这可能会生成这些内容。
我正在寻找关于什么可能导致如此多的 int32/64 堆分配的任何建议,以及一些隔离这些分配的技术(调用堆栈会很好,但可能会限制性能)。
最佳答案
I am guessing this is somehow indicating that I am creating a lot of pointers on the heap in some unexpected way?
听起来您更有可能对我装箱了很多 int
和 long
值。
CallSite
部分听起来像是您经常使用 dynamic
(或者在代码中使用非常频繁的部分),这很容易导致更多装箱比静态类型的代码。
我会尝试隔离分配大量对象的代码的特定区域 - 例如,如果您可以仅使用特定的代码路径,那将使您更清楚地了解哪些路径产生的垃圾比你会期待的。看看任何使用 dynamic
的地方,看看你是否真的需要 - 尽管你不应该觉得你必须删除 所有 dynamic
的使用> 通过任何方式;很可能存在一个可以微优化的特定“热点”。
要考虑的另一件事是此分配实际花费了您多少。你说你正试图大幅减少它——你真的需要吗?如果所有这些对象的生命周期都非常短,您可能会发现通过降低分配率并不能显着提高性能。您应该测量在垃圾收集上花费的时间,以确定这可能有多有效。
关于c# - Int/Int64 .Net 内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18681102/