【问题标题】:Is it possible to read all strings in the intern pool?是否可以读取实习生池中的所有字符串?
【发布时间】:2017-07-25 20:10:14
【问题描述】:

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

所以我的问题是:

  • 是否可以读取当前在实习生池中的所有字符串?
  • 有没有办法获得对每个实习字符串的引用计数?
  • 是否可以从单独的进程空间读取实习池?
  • 如果这些都不可能,那么不允许这些用例的原因是什么?

在某些情况下监控内存使用情况时,我可以看到这有点有用。在处理敏感信息时它也可能很有用(尽管我认为SecureString 在许多情况下会更可取)。

据我所知,与字符串实习相关的唯一公共方法是 String.Intern(string)String.IsInterned(string)

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

【问题讨论】:

  • “不允许这些用例的原因是什么?” 因为every feature starts with -100 points 和团队正在做真正有用的事情。
  • "f 这些都不可能,不允许这些用例的原因是什么?"这些不是用例——它们是 API 功能请求没有用例。一个用例会解释为什么你想要做这些事情。你后来说你没有试图解决一个真正的问题这一事实表明你没有一个用例。就个人而言,我不赞成将无用的功能混杂在一起。
  • 可能。通过 Microsoft.Diagnostics.Runtime 中的 ClrMD API 获取所有对象的列表,并使用 IsInterned 查找所有已插入字符串。 API 还可能提供您需要的其他统计信息。除非您正在编写调试器,否则没有理由这样做。

标签: c# .net string clr


【解决方案1】:

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

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

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

.loadby sos clr

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

!DumpHeap -strings

你可以看到堆中的所有字符串对象。

至于告诉您正在查看的该列表中的对象是否已被实习,我不完全确定如何。希望如果你问一个关于 WinDbg 的新问题以及如何判断一个字符串是否被保留,有人可能能够回答。

【讨论】:

    【解决方案2】:

    您可以使用基于 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
    

    这将为您提供一个指标,您有多少重复字符串以及其中哪些可能对实习有意义。要找出哪个对象引用了特定字符串,您可以添加

    -显示地址

    显示每个可能值得实习的字符串的第一个地址。然后,您可以使用 Windbg 和 !GCRoot 地址找出哪个对象保存该字符串,这应该让您了解需要在哪个类中添加 String.Intern 调用。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-14
      • 2021-02-10
      • 2014-12-20
      • 2016-08-08
      • 2013-10-03
      • 2013-08-11
      • 1970-01-01
      相关资源
      最近更新 更多