如何处理大字符串和有限的内存

时间:2010-01-27 16:04:13

标签: java string memory out-of-memory

我有一个文件,我从中读取数据。 此文件中的所有文本都存储在String变量(一个非常大的变量)中。 然后在我的应用程序的另一部分,我想要遍历此字符串并逐步提取有用的信息(解析字符串)。

同时我的内存已满,OutOfMemory异常使我无法进一步处理。 我认为在从文件中读取输入流时直接处理数据会更好。但是对于组织目标,我想将String传递给我的应用程序中的另一部分。

如何防止内存溢出?

4 个答案:

答案 0 :(得分:6)

您应该使用BufferedInputReader而不是将所有内容存储到一个大字符串中。

如果要解析的内容恰好在同一行上,那么StringTokenizer可以很好地工作,否则你必须设计一种方法来从文件中读出你想要解析语句的内容,然后应用每个语句的StringTokenizer。

答案 1 :(得分:6)

如果您可以稍微放松一下您的要求,可以实施文件支持的java.lang.CharSequence

支持CharSequence many places in the JDK(字符串是CharSequence)。所以这是基于Reader的实现的一个很好的替代方案。

答案 2 :(得分:4)

其他人建议您一次阅读和处理部分文件。如果可能的话,其中一种方式会更好。

但是,如果这是不可能的,并且您可以在指示时将String最初加载到内存中,但稍后解析此字符串会产生问题,则可以使用子字符串。在Java中,子字符串映射在原始char数组之上,只为内部Object获取内存,然后是开始和长度int指针。

因此,当您找到要单独保留的字符串的一部分时,请使用以下内容:

String piece = largeString.substring(foundStart, foundEnd);

如果您改为使用此代码或代码在内部执行此操作,则内​​存使用将显着增加:

new String(largeString.substring(foundStart, foundEnd));

请注意,出于这个原因,您必须谨慎使用String.substring()。你可以有一个非常大的字符串,你从中获取一个子字符串,然后丢弃对原始字符串的引用。问题是子字符串仍然引用原始的大char数组。 GC也不会释放,直到子串也被删除。在这种情况下,实际使用new String(...)以确保GC将丢弃未使用的大型数组是有用的(这是您应该使用new String(...)的少数情况之一)。

另一种技术,如果你希望有很多小字符串,并且它们可能具有相同的值,但来自外部源(如文件),则在创建新的后使用.intern()字符串。

注意:这取决于你真正不应该注意的String的实现,但在大型应用程序的实践中,有时你必须依赖这些知识。请注意,Java的未来版本可能会改变这种情况(尽管不太可能)。

答案 3 :(得分:1)

您必须检查您的算法以处理大数据。您必须处理chunk-by-chank此数据,或使用随机文件访问而不将数据存储在内存中。例如,您可以使用StringTokenizer或StreamTokenizer作为所谓的@Zombies。 您可以看到parser-lexer技术:当解析器解析某个表达式时,它会要求lexer读取下一个lexem(令牌),但不会立即读取整个输入流。