【问题标题】:How to reduce memory footprint on .NET string intensive applications?如何减少 .NET 字符串密集型应用程序的内存占用?
【发布时间】:2012-03-09 18:45:28
【问题描述】:

我有一个应用程序在内存中有大约 1,000,000 个字符串出于性能原因。我的应用程序消耗约 200 MB RAM。

我想减少字符串消耗的内存量。

我知道 .NET 表示 UTF-16 编码的字符串(每个字符 2 个字节)。我的应用程序中的大多数字符串都包含纯英文字符,因此以 UTF-8 编码存储它们的效率将是 UTF-16 的 2 倍。

有没有办法在允许标准字符串函数的同时以 UTF-8 编码将字符串存储在内存中? (我的需求主要包括 IndexOf 和 StringComparison.OrdinalIgnoreCase)。

【问题讨论】:

  • 您是否必须将所有 1,000,000 个字符串加载到内存中?您能否提供更多详细信息,说明您对内存中的所有这些字符串究竟做了什么?
  • 为什么 200MB 是个问题,你有内存不足或内存不足的问题吗?
  • 但是,200MB 是个问题吗?您的用户是否有少量可用内存?请注意,我也不是说 200MB 是可以接受的,这取决于应用程序,但通常,当人们“抱怨”内存使用和应用程序时,他们不会因为一个原因而认为他们拥有所有可用的内存;让应用程序运行得更快!
  • 我喜欢将内存使用比作车库空间使用。如果你有一个可以停放大约 10 辆车的大车库,你为什么要在角落的长凳上争论一平方英尺?
  • @LasseV.Karlsen - 如果你照顾好美分,美元就会照顾好自己。

标签: c# .net string utf-8 utf-16


【解决方案1】:

不幸的是,您无法更改字符串的 .Net 内部表示。我的猜测是 CLR 针对多字节字符串进行了优化。

您正在处理的是著名的 Space-time tradeoff 范例,它指出为了获得内存,您必须使用更多的处理器,或者您可以通过使用一些来节省处理器记忆。

也就是说,看看一些注意事项here。如果我是你,一旦确定内存增益对你来说足够了,请尝试编写你自己的“字符串”类,它使用 ASCII 编码。这可能就足够了。

更新:

更多关于钱的信息,您应该查看 StackOverflow 传奇人物 Jon Skeet 撰写的这篇帖子“Of memory and strings”,该帖子解决了您面临的问题。抱歉,我没有立即提及,我花了一些时间才找到 Jon 的确切帖子。

【讨论】:

    【解决方案2】:

    有没有办法在允许标准字符串 > 函数的同时以 UTF-8 编码将字符串存储在内存中? (我的需求主要包括 IndexOf 和 StringComparison.OrdinalIgnoreCase)。

    您可以存储为字节数组,并提供您自己的 IndexOf 实现(因为将 IndexOf 转换回字符串可能会对性能造成巨大影响)。为此使用 System.Text.Encoding 函数(最好的办法是执行构建步骤以转换为字节,然后从磁盘读取字节数组 - 如果需要,仅转换回字符串以供显示)。

    您可以将它们存储在 C/C++ 库中,让您使用单字节字符串。您可能不想将它们编组回来,但您可能只是编组结果(我假设这里正在进行某种搜索)而没有太多的性能命中。 C++/CLI 可能会使这更容易(通过能够在 C++/CLI 中编写搜索代码,但在 C++ 中编写字符串“database”)。

    或者,您可以重新审视需要内存中所有字符串的初始性能问题。嵌入式数据库、索引等可以加快速度减少内存使用 - 并且更易于维护。

    【讨论】:

    • 如何实现字符的 IgnoreCase 比较? C/C++ 中是否有任何 UTF-8 库/表示形式?
    • @DxCK 你遇到的问题是,如果你把自己限制在 8 位,你不支持世界上使用的大部分语言,即使是 C++ 和 UTF8
    • @Chris S UTF8 编码如何限制语言?
    • 我建议使用预先计算的大小写转换创建一个简单的查找表 - 因为您将编码为 8 位,所以您需要一个 256 条目表,您可以通过查找简单地进行转换(例如 @987654321 @)
    • @sgorozco - 我认为您将 UTF-8(即 Unicode)与纯 ol' ASCII 混淆了。 UTF-8 将 ASCII 字符存储为单字节,但可变宽度以存储 Unicode 的其余部分。
    【解决方案3】:

    如果将其存储为字节数组会怎样?当您需要对其进行一些操作时,只需恢复为字符串即可。我会创建一个类来设置和获取在内部将其存储为字节数组的字符串。

    到字节数组:

    string s = "whatever";
    byte[] b = System.Text.Encoding.UTF8.GetBytes(s);
    

    到字符串:

    string s = System.Text.Encoding.UTF8.GetString(b);
    

    【讨论】:

    • 我试过了。转换回 String 几乎没有性能成本:分配内存,从 UTF-8 转换为 UTF-16,然后 GC 它。对于 1,000,000 个字符串,这是非常可观的成本。
    • @DxCK “然后 GC 它” - 你的意思是什么?
    • 你想要什么...性能还是更小的占用空间? :) 您的应用程序是否持续需要每个字符串?如果不是,也许只存储一段时间未使用的字符串。创建一个执行某种内部“内存收集”而不是垃圾收集的类。
    • 我猜字节数组不好,因为他需要搜索字符串
    • 如果您重写 String 类但使用您喜欢的字符编码,您可以使用字节数组并具有良好的性能。是的,记住数据结构。
    【解决方案4】:

    尝试使用内存数据库作为“存储”并使用 SQL 与数据交互...例如,SQLite 可以部署为您的应用程序的一部分(仅包含 1-2 个可以放置在与您的应用程序相同的文件夹)...

    【讨论】:

      【解决方案5】:

      如果您创建自己的 UTF-8 字符串类 (UTF8String?) 并提供对 String 的隐式转换会怎样?为了记忆,你会牺牲一些速度,但这可能就是你想要的。

      【讨论】:

      • 我试过了。转换回字符串几乎没有性能成本。从 UTF-8 转换为 UTF-16,然后对其进行 GC。对于 1,000,000 个字符串,这是非常可观的成本。
      猜你喜欢
      • 2016-11-09
      • 1970-01-01
      • 2012-03-25
      • 1970-01-01
      • 2023-03-21
      • 2010-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多