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

hsm*_*mit 6 java memory string out-of-memory

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

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

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

Zom*_*ies 6

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

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


Tho*_*ung 6

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

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


Kev*_*ock 5

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

但是,如果这是不可能的,并且您能够String按照指示将初始加载到内存中,但是稍后在解析此字符串时会出现问题,则可以使用子字符串。在Java中,子字符串映射在原始char数组的顶部,仅占用基础的内存Object,然后占用int指针的开始和长度。

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

String piece = largeString.substring(foundStart, foundEnd);
Run Code Online (Sandbox Code Playgroud)

如果改为使用此代码或内部执行此操作的代码,则内存使用量将急剧增加:

new String(largeString.substring(foundStart, foundEnd));
Run Code Online (Sandbox Code Playgroud)

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

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

注意:这确实取决于String您实际上不必了解的实现,但是在实践中,对于大型应用程序,有时您确实必须依赖该知识。请注意,Java的未来版本可能会对此进行更改(尽管不太可能)。