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

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

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

我该怎么做才能防止内存溢出?

您应该使用BufferedInputReader而不是将其全部存储到一个大字符串中。

如果您要解析的内容恰好在同一行上,那么StringTokenizer将非常好用,否则您必须设计一种方法来从文件中读取您想要解析语句的内容,然后将StringTokenizer应用于每个语句。

如果你可以稍微放松一下你的需求,你可以实现一个由你的文件支持的java.lang.CharSequence 。

JDK中的许多地方都支持CharSequence(字符串是CharSequence)。 因此,这是基于Reader的实现的一个很好的替代方案。

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

但是,如果这是不可能的,并且您可以在指示时将String最初加载到内存中,但稍后解析此字符串会产生问题,则可以使用子字符串。 在Java中,子字符串映射在原始char数组之上,只为基础Object获取内存,然后是start和length 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的未来版本可能会改变这种情况(尽管不太可能)。

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