Java 字符串内存泄漏
我不是java专家。
我的代码正在将文件读入String
。此代码每 5 分钟执行一次。 文件的大小各不相同。有时是 100 行,有时是 1000 行。
几天后,我经历了“内存不足”。
我的问题是,当我的代码超出读取文件函数
的范围时,Java垃圾收集字符串吗?
我在互联网上阅读很困惑。有人说它不会被删除并使用StringBuffer
。
// Demonstrate FileReader.
import java.io.*;
class FileReaderDemo {
public static void read(BufferedReader br) throws Exception {
long length = 0;
String s;
while (true) {
s = br.readLine();
s += "abcd";
if (s == null) {
break;
}
length += s.length();
//System.out.println(s);
}
System.out.println("Read: " + (length / 1024 / 1024) + " MB");
}
public static void main(String args[]) throws Exception {
//FileReader fr = new FileReader("FileReaderDemo.java");
FileReader fr = new FileReader("big_file.txt.1");
BufferedReader br = new BufferedReader(fr);
String s;
read(br);
fr = new FileReader("big_file.txt.1");
br = new BufferedReader(fr);
read(br);
fr = new FileReader("big_file.txt.1");
br = new BufferedReader(fr);
read(br);
fr = new FileReader("big_file.txt.1");
br = new BufferedReader(fr);
read(br);
BufferedReader in = new BufferedReader(new InputStreamReader(System. in )); in .readLine();
fr.close();
}
}
I am not java expert.
My code is reading a file into a String
. This code gets executed every 5 minutes.
The size of file varies. Sometimes it is 100 sometimes it is 1000 lines.
I am experience Out Of Memory, after some days.
The question I have is, when my codes goes out of scope of the Reading file function
, does Java garbage collect the String?
I am pretty confused by reading on the internet. Some people says it does not get deleted and use StringBuffer
.
// Demonstrate FileReader.
import java.io.*;
class FileReaderDemo {
public static void read(BufferedReader br) throws Exception {
long length = 0;
String s;
while (true) {
s = br.readLine();
s += "abcd";
if (s == null) {
break;
}
length += s.length();
//System.out.println(s);
}
System.out.println("Read: " + (length / 1024 / 1024) + " MB");
}
public static void main(String args[]) throws Exception {
//FileReader fr = new FileReader("FileReaderDemo.java");
FileReader fr = new FileReader("big_file.txt.1");
BufferedReader br = new BufferedReader(fr);
String s;
read(br);
fr = new FileReader("big_file.txt.1");
br = new BufferedReader(fr);
read(br);
fr = new FileReader("big_file.txt.1");
br = new BufferedReader(fr);
read(br);
fr = new FileReader("big_file.txt.1");
br = new BufferedReader(fr);
read(br);
BufferedReader in = new BufferedReader(new InputStreamReader(System. in )); in .readLine();
fr.close();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
每个人都有可以学习的东西。
听起来不是很大,也不是很频繁。应该不是问题。
您应该能够获得堆转储并查看内存不足的位置以及原因。
当不再可以通过强引用访问它时,可以收集它。
听起来很困惑,听起来你来对地方了。我从来没有听说过这个。
Everyone has something they can learn.
Doesn't sound very large or very often. Shouldn't be a problem.
You should be able to get a heap dump and see where you have run out of memory and why.
It can be collected when it is no longer reachable via a Strong reference.
Sounds like you came to the right place. I have never heard that one.
您的
read
方法永远不会终止。一旦到达文件末尾,您只需继续将字符串"nullabcd"
添加到s
即可,永远如此。编辑:忘记了,
s
每次都会重新分配。尽管如此,我还是看不出你的read
方法如何终止。Your
read
method will never terminate. Once you reach the end of the file, you just continue adding the string"nullabcd"
tos
, forever.EDIT: forget that,
s
is re-assigned each time. Still, I can't see how yourread
method can terminate.您发布的代码不会泄漏内存。但是,
while (true)
循环永远不会终止,因为在测试时s
永远不会是null
。让我们对其进行一些更改以使其“工作”。
这段代码也不会泄漏内存,因为当方法返回时(如果不是之前),在方法中创建的字符串都将成为垃圾回收的候选者。
每次执行
s += ss;
时,都会创建一个新字符串,其中包含当前s
中的所有字符以及ss
中的字符。假设有 N 行平均包含 L 个字符,则s += ss;
语句将被调用 N 次,将创建 N 个字符串,并平均复制(N * L) ^2 / 2
个字符。然而,创建
StringBuilder
有一个很好的理由,那就是减少字符串分配和字符复制的数量。让我们重写该方法以使用StringBuilder
;即替换不同步的StringBuffer
。此版本将重新分配 StringBuilder 的内部字符数组最多
log2(N)
次并复制最多2 * N * L< /code> 字符。
总结 - 使用 StringBuilder 是一个好主意,但不是因为内存泄漏。如果存在内存泄漏,它不在原始示例代码或修复版本中。
The code that you have posted won't leak memory. However, the
while (true)
loop will never terminate becauses
will never benull
at the point that you test it.Lets change it a bit to make it "work"
This code doesn't leak memory either because the Strings created in the method will all be candidates for garbage collection when the method returns (if not before).
Each time we execute
s += ss;
a new string is created consisting of all of the characters currently ins
and the characters inss
. Assuming there are N lines containing an average of L characters, thes += ss;
statement will be called N times, will create N strings, and will copy on average(N * L)^2 / 2
characters.However, there is a good reason to make a
StringBuilder
and that is to reduce the amount of String allocation and character copying that goes on. Lets rewrite the method to use aStringBuilder
; i.e. a replacement forStringBuffer
that is not synchronized.This version will reallocate the StringBuilder's internal character array at most
log2(N)
times and copy at most2 * N * L
characters.Summary - using the StringBuilder is a good idea, but not because of memory leaks. If you have a memory leak, it is not in the original sample code or in the fixed version.
像下面这样更改程序以消耗更少的内存。内存消耗的一个巨大来源是由于您重复的字符串连接
s += "abcd";
- 避免这种情况,您可能会减少一半以上的内存消耗(未经测试 - 如果您自己分析一下)你想知道)。change the program like below to consume less memory. A huge source of memory consumption is due to your repeated string concatenation of
s += "abcd";
- avoid that and you'll probably more than halve your memory consumption (not tested - profile it yourself if you want to know).正如其他人指出的那样,这段代码永远不会终止。您发布的代码似乎不是您遇到问题的原始代码。
在没有看到实际代码的情况下很难诊断,但是一旦没有从代码的其他部分引用字符串,它们肯定会被垃圾收集。
大胆猜测:使用完 Readers 和 InputStreams 后,您是否会调用
close()
?如果没有,这可能是内存不足错误的原因。As pointed out by others this code never terminates. It looks like the code you posted is not the original code you are having problems with.
Hard to diagnose without seeing the actual code, but Strings will definitely be garbage collected once they are not referenced from other parts of the code.
Wild guess: Are you calling
close()
on your Readers and InputStreams once you're done with them? If not, this could be the cause of your out of memory errors.