我有一个文件从中读取数据。 该文件中的所有文本都存储在一个字符串变量(一个非常大的变量)中。 然后在我的应用程序的另一部分,我想遍历这个字符串并逐步提取有用的信息(解析字符串)。如何处理大字符串和有限内存
与此同时,我的内存变满,OutOfMemory异常让我无法进一步处理。 我认为从文件中读取输入流时直接处理数据会更好。但为了组织的目的,我想将字符串传递给我的应用程序中的另一部分。
我应该怎么做才能防止内存溢出?
我有一个文件从中读取数据。 该文件中的所有文本都存储在一个字符串变量(一个非常大的变量)中。 然后在我的应用程序的另一部分,我想遍历这个字符串并逐步提取有用的信息(解析字符串)。如何处理大字符串和有限内存
与此同时,我的内存变满,OutOfMemory异常让我无法进一步处理。 我认为从文件中读取输入流时直接处理数据会更好。但为了组织的目的,我想将字符串传递给我的应用程序中的另一部分。
我应该怎么做才能防止内存溢出?
您应该使用BufferedInputReader而不是将其全部存储到一个大字符串中。
如果你想要解析的东西恰好在同一行上,那么StringTokenizer会很好地工作,否则你必须设计一种方法来读取你想从文件中解析出来的语句,然后将StringTokenizer应用到每个声明。
如果您可以稍微放松您的需求,您可以实施由您的文件支持的java.lang.CharSequence。
支持CharSequence many places in the JDK(一个字符串是一个CharSequence)。所以这是基于Reader的实现的一个很好的选择。
您必须检查处理大量数据的算法。您必须逐个处理这些数据,或者使用随机文件访问而不将数据存储在内存中。例如,你可以使用StringTokenizer或StreamTokenizer作为@Zombies。 您可以看到解析器 - 词法分析器技术:当解析器解析某个表达式时,它会要求词法分析器读取下一个lexem(令牌),但不会一次读取整个输入流。
其他人建议您一次读取和处理文件的某些部分。如果可能的话,其中一种方法会更好。
但是,如果这是不可能的,并且您能够将String
最初加载到内存中,但是您稍后解析了此字符串会产生问题,您可能可以使用子字符串。在Java中,子字符串映射在原始的char
数组的顶部,并且仅占用基地Object
的内存,然后是开始和长度的int指针。
所以,当你发现你想要单独保留字符串的一部分,使用类似:
String piece = largeString.substring(foundStart, foundEnd);
如果你不是这个或代码,内部做到这一点,那么内存的使用将显着增加:
new String(largeString.substring(foundStart, foundEnd));
请注意,您必须谨慎使用String.substring()
这个原因。你可以有一个非常大的字符串,你需要一个子字符串,然后放弃你对原始字符串的引用。问题是子字符串仍然引用原始大型数组。直到子字符串也被移除后,GC才会释放它。在这种情况下,实际使用new String(...)
以确保未使用的大数组将被GC丢弃(这是您应该使用new String(...)
的少数情况之一)。
另一种技术,如果你期望有很多小字符串,并且这些字符串可能具有相同的值,但来自外部源(如文件),则在创建新字符串后使用.intern()
。
注意:这取决于String
的实现,您实际上不应该知道这一点,但实际上对于大型应用程序,有时您必须依赖这些知识。请注意,Java的未来版本可能会改变这一点(虽然不太可能)。
难道你不能用一个读者(例如BufferedReader)来逐个解析文件吗? – 2010-01-27 16:09:43