注意:我的案例是在一个旧 API 的生态系统中,它只适用于字符串,没有现代 .NET 添加。
所以我非常需要没有分配的可变字符串。字符串每 X 毫秒更新一次,因此您可以在几分钟内计算出它可以产生多少垃圾(StringBuilder 甚至根本不接近相关)。我目前的方法是预先分配固定大小的字符串,并通过固定、直接写入字符以及在容量达到时静默掉落或抛出来对其进行变异。
这工作正常。分配的字符串是长期存在的,因此最终 GC 会将其提升到 Gen2 并且固定不会对其造成太大影响,从而最大限度地减少开销。但是有两个主要问题:
- 因为字符串是固定的,我必须用它来填充它,
\0
虽然到目前为止这对所有默认的 NET/MONO 功能和第 3 方的东西都很好,但无法告诉其他东西在 len 为 1024 时会有什么反应,但最后 100 是\0
- 我无法调整它的大小,因为这会导致分配。我可以一次分配一次蓝月亮,但由于字符串是相当动态的,我无法确定它何时会尝试进一步扩展或缩小。我可以使用“仅扩展”方法,这样我只在需要扩展时分配,但是,这有填充开销的缺点(如果字符串扩展为 5k 个字符,但下一个字符串只是 3k - 2k 个字符将被填充额外的周期) 以及额外的内存使用。我不确定 GC 对 mchuge 的感觉如何,通常在 Gen2 中而不是在 LOH 中固定字符串。另一种方法是池可重用字符串对象,但是,这具有更高的内存和 GC 开销 + 查找开销。
由于目标字符串必须存在相当长的时间,我正在考虑通过字节缓冲区将其移动到Unmanaged memory中。这将消除 GC 的负担(固定惩罚开销),并且我可以以比托管堆更低的成本重新调整大小/重新分配。
我很难理解的是- 我怎么可能对分配的非托管缓冲区的特定部分进行切片并将其包装为正常的网络字符串以在托管空间/代码中使用?比如,将它传递给Console.WriteLine
在屏幕上绘制 UI 标签并接受字符串的第 3 方库。这甚至可行吗?
PS 据我所知,NET5 的计划(我认为将在 NET6 中最终确定)您将不再能够改变字符串之类的东西(在运行时被阻止或未定义的故障)。他们的解决方案似乎是我所描述的 POH,具有相同的限制。