java字符串表表容量_java – 我可以使用什么符号表来存储~50 mil的字符串,快速查找而不会耗尽堆空间?...
我有一個約5000萬字符串的文件,我需要在啟動時添加到某種符號表中,然后以合理的速度搜索幾次.
我嘗試使用DLB trie,因為查找會相對較快,因為所有字符串都是< 10個字符,但在填充DLB時,我會得到超出GC開銷限制或outofmemory - 堆空間錯誤.使用HashMap發現了相同的錯誤.這是一個由分級器編譯和運行的賦值,所以我寧愿不只是分配更多的堆空間.是否有不同的數據結構可以減少內存使用,同時仍然有合理的查找時間?
解決方法:
如果您期望低前綴共享,那么trie可能不是您的最佳選擇.
由于您只在啟動時加載查找表一次,并且您的目標是內存占用率低且查找速度“合理”,因此最佳選擇可能是排序數組和二進制搜索查找.
首先,將數據加載到數組中.由于您可能不知道前面的大小,因此您將加載到ArrayList中.然后從列表中提取最終數組.
假設您加載了5000萬個10個字符的字符串,內存將是:
10 character string:
String: 12 byte header + 4 byte 'hash' + 4 byte 'value' ref = 24 bytes (aligned)
char[]: 12 byte header + 4 byte 'length' + 10 * 2 byte 'char' = 40 bytes (aligned)
Total: 24 + 40 = 64 bytes
Array of 50 million 10 character strings:
String[]: 12 byte header + 4 byte 'length' + 50,000,000 * 4 byte 'String' ref = 200,000,016 bytes
Values: 50,000,000 * 64 bytes = 3,200,000,000 bytes
Total: 200,000,016 + 3,200,000,000 = 3,400,000,016 bytes = 3.2 GB
當您轉換ArrayList< String>時,您將需要另一個String []副本. to String []. Arrays.sort()操作可能需要50%的數組大小(~100,000,000字節)用于臨時存儲,但如果在排序之前為GC發布了ArrayList,則可以重用該空間.
因此,總需求約為3.5 GB,僅適用于符號表.
現在,如果空間確實非常珍貴,你可以擠壓它.如您所見,String本身在64字節中增加了24字節的開銷.您可以使符號表直接使用char [].
此外,如果您的字符串都是US-ASCII或ISO-8859-1,則可以將char []轉換為byte [],從而節省一半的字節.
組合在一起,將值大小從64字節減少到32字節,總符號表大小從3.2 GB減少到1.8 GB,或在加載期間大約2 GB.
UPDATE
假設輸入的字符串列表已經排序,下面是如何執行此操作的示例.作為MCVE,它只使用一個小的靜態數組作為輸入,但您可以輕松地從文件中讀取它們.
public class Test {
public static void main(String[] args) {
String[] wordsFromFile = { "appear", "attack", "cellar", "copper",
"erratic", "grotesque", "guitar", "guttural",
"kittens", "mean", "suit", "trick" };
List wordList = new ArrayList<>();
for (String word : wordsFromFile) // Simulating read from file
wordList.add(word.getBytes(StandardCharsets.US_ASCII));
byte[][] symbolTable = wordList.toArray(new byte[wordList.size()][]);
test(symbolTable, "abc");
test(symbolTable, "attack");
test(symbolTable, "car");
test(symbolTable, "kittens");
test(symbolTable, "xyz");
}
private static void test(byte[][] symbolTable, String word) {
int idx = Arrays.binarySearch(symbolTable,
word.getBytes(StandardCharsets.US_ASCII),
Test::compare);
if (idx < 0)
System.out.println("Not found: " + word);
else
System.out.println("Found : " + word);
}
private static int compare(byte[] w1, byte[] w2) {
for (int i = 0, cmp; i < w1.length && i < w2.length; i++)
if ((cmp = Byte.compare(w1[i], w2[i])) != 0)
return cmp;
return Integer.compare(w1.length, w2.length);
}
}
產量
Not found: abc
Found : attack
Not found: car
Found : kittens
Not found: xyz
標簽:java,memory
來源: https://codeday.me/bug/20190608/1199027.html
總結
以上是生活随笔為你收集整理的java字符串表表容量_java – 我可以使用什么符号表来存储~50 mil的字符串,快速查找而不会耗尽堆空间?...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java yyyy m d_日期-Jav
- 下一篇: Win10安全特性之执行流保护