是否可以读取实习生池中的所有字符串?

Is it possible to read all strings in the intern pool?

众所周知,在某些特定情况下,当在 C# 中使用字符串时,CLR 会将字符串驻留作为一种优化。

所以我的问题是:

我发现这在某些情况下监视内存使用情况时有点用处。它在处理敏感信息时也很有用(尽管我认为 SecureString 在许多情况下更可取)。

据我所知,与字符串驻留相关的唯一 public 方法是 String.Intern(string)String.IsInterned(string)

我是出于好奇才问的,并不是想解决真正的问题。我意识到基于字符串实习生池执行任何逻辑都不是一个好主意。

通过代码查找驻留字符串没有用例,因此它的功能未添加到语言中。

然而,在调试程序时查找内存中的字符串是一个非常常见的用例,并且有工具可以做到这一点。

您将需要使用 Windows SDK 附带的工具 WinDbg.exe。启动它并将其附加到您的程序后,您可以执行命令

.loadby sos clr

这将加载用于调试 .NET 应用程序的扩展。完成后,您可以执行命令

!DumpHeap -strings

并且您可以看到堆中的所有字符串对象。

至于判断您正在查看的列表中的对象是否被 interned,我不太确定如何判断。希望如果你问一个关于 WinDbg 的新问题,以及如何判断一个字符串是否被 interned,也许有人能够回答。

您可以使用基于 ClrMDMemAnalyzer 分析对实习有意义的字符串和重复项。

https://github.com/Alois-xx/MemAnalyzer

C>MemAnalyzer.exe -dstrings -f 50KStringsx64.dmp

    Strings(Count)  Waste(Bytes)    String
    500             20,958          String 0
    500             20,958          String 1
    500             20,958          String 2
    500             20,958          String 3
    500             20,958          String 4
    500             20,958          String 5

Summary
==========================================
Strings                       61,330 count
Allocated Size             2,529,742 bytes
Waste Duplicate Strings    2,515,898 bytes

这会给你一个指标,你有多少重复的字符串,其中哪些可能对实习生有意义。要找出哪个对象引用了特定的字符串,您可以添加

-showAddress

显示每个可能值得驻留的字符串的首地址。然后你可以使用 Windbg 和 !GCRoot 地址找出哪个对象保存这个字符串,这应该让你知道你需要在哪个 class 添加 String.Intern 调用。

请注意.NET String.Intern 池永远不会释放引用。如果您正在处理具有不同内容的大型数据集,您应该使用自己的词典池,以便能够在卸载当前数据集并加载下一个数据集时释放所有驻留的字符串。