12MB 存储 120,000 个字大约是每个字 100 个字节。可能至少有 32 个字节是字符串开销。如果单词平均有 10 个字母并且它们被存储为 2 字节字符,那么这将占用另外 20 个字节。然后是对 HashSet 中每个字符串的引用,这可能是另外 4 个字节。剩下的 44 个字节可能是 HashSet 条目和索引开销,或者我上面没有考虑过的东西。
最容易解决的问题是 String 对象本身的开销,这可能会占用比存储实际字符数据所需的内存更多的内存。因此,您的主要方法是开发一种自定义表示,以避免为每个字符串存储单独的对象。在执行此操作的过程中,您还可以摆脱 HashSet 开销,因为您真正需要的只是一个简单的单词查找,这可以通过对将成为您的自定义实现的一部分的数组进行简单的二进制搜索来完成。
您可以将自定义实现创建为 int 类型的数组,每个单词都有一个元素。这些 int 元素中的每一个都将被分解为包含长度和偏移量的子字段,这些子字段指向一个单独的 char 类型的后备数组。将这两者放入管理它们的类中,并支持公共方法,允许您检索和/或转换给定字符串索引和可选字符索引的数据和单个字符,并在单词列表上执行简单搜索您的拼写检查功能所需的。
如果基础字符串数据的字符数不超过 16777216 个(例如,120,000 个字符串乘以 10 个字符的平均长度 = 120 万个字符),则可以取每个 int 的低 24 位并存储起始偏移量将每个字符串放入您的 char 数据的后备数组中,并取每个 int 的高 8 位并将相应字符串的大小存储在那里。
您的 char 数据会将您以前的字符串挤在一起,没有任何分隔符,完全依赖 int 数组来了解每个字符串的开始和结束位置。
采用上述方法,您的 120,000 个单词(平均每个单词 10 个字母)将需要大约 2,400,000 字节的支持数组数据和 480,000 字节的整数索引数据(120,000 x 4 字节),总共需要 2,880,000 字节,这比您上面报告的当前 12MB 量节省了大约 75%。
数组中的单词将按字母顺序排序,您的查找过程可以是对 int 数组的简单二进制搜索(从 char 数组中为每个测试检索相应的单词),这应该非常有效。
如果您的文字恰好完全是 ASCII 数据,您可以通过将支持数据存储为字节而不是字符来额外节省 1,200,000 字节。
如果您需要更改这些字符串,这可能会变得更加困难。显然,在你的情况下(拼写检查器),你不需要(除非你想支持用户添加到列表中,这无论如何都是不常见的,因此重写 char 数据和索引以添加或删除单词可能可以接受)。