所以我有一个小客户端代码
public class Client {
private static Socket socket;
private static ObjectOutputStream out;
public static void main(String[] args) {
while (true) {
try {
if (socket != null) {
out.writeObject("Hello...");
Thread.sleep(1500);
} else {
socket = new Socket("myhost", 1234);
out = new ObjectOutputStream(socket.getOutputStream());
System.out.println("connected to server");
}
} catch (final Exception e) {
//set socket to null for reconnecting
}
}
}
}让我烦恼的是,当我使用javaw.exe运行代码时,我看到java每2-3秒就会占用大约10 me的内存。所以内存使用量在不断增长..。
java真的那么糟糕吗?还是有其他问题?
我在while循环中运行了这段代码一段时间,内存使用量增加了1000 kb。java gargabe使用后不收集“tmp”变量吗?
try {
if (socket == null) {
final Socket tmp = new Socket("localhost", 1234);
if (tmp != null) {
socket = tmp;
}
Thread.sleep(100);
}
} catch (final Exception e) {
}发布于 2011-02-25 22:05:29
因此,我已经为您的客户机编写了一个简单的测试服务器,现在我正在运行这两个测试服务器,而且内存使用量似乎没有增加。
import java.net.*;
import java.io.*;
/**
* example class adapted from
* http://stackoverflow.com/questions/5122569/why-is-java-constantly-eating-more-memory
*/
public class Client {
private static Socket socket;
private static ObjectOutputStream out;
private static void runClient() {
while (true) {
try {
if (socket != null) {
out.writeObject("Hello...");
Thread.sleep(100);
System.out.print(",");
} else {
socket = new Socket("localhost", 1234);
out = new ObjectOutputStream(socket.getOutputStream());
System.out.println("connected to server");
}
} catch (final Exception e) {
//set socket to null for reconnecting
e.printStackTrace();
return;
}
}
}
private static void runServer() throws IOException{
ServerSocket ss = new ServerSocket(1234);
Socket s = ss.accept();
InputStream in = s.getInputStream();
byte[] buffer = new byte[500];
while(in.read(buffer) > 0) {
System.out.print(".");
}
}
public static void main(String[] args)
throws IOException
{
if(args.length > 0) {
runServer();
}
else {
runClient();
}
}
}你在做什么不同?
因此,我更详细地研究了这个程序的内存使用情况,并为此找到了一个有用的工具,即隐藏在系统开发菜单中的"Java监视和管理控制台“:-)
以下是运行客户端程序时内存使用情况的屏幕截图(请记住,每100 ms我发送一个对象).

我们可以看到,内存使用有锯齿曲线-它是线性增长,然后是垃圾收集,它正在下降到基本的使用。在一些初始阶段之后,VM正在更频繁地执行GC (因此更快)。现在没问题。
这里有一个变体程序,我没有总是发送相同的字符串,而是每次发送一个不同的字符串:
private static void runClient() {
int i = 0;
while (true) {
try {
i++;
if (socket != null) {
out.writeObject("Hello " + i + " ...");
Thread.sleep(100);
System.out.print(",");(其余的和上面一样)。我认为这需要更多的内存,因为ObjectOutputStream必须记住已经发送了哪些对象,以便能够重用它们的标识符,以防它们再次出现。
但不,看起来很相似:

39到40之间的小不规则点是由“执行GC”按钮制作的手动全GC --尽管没有什么变化。
我让最后一个程序运行得更长一些,现在我们看到ObjectOutputStream仍然保存着对String的引用。

在半小时内,我们的程序消耗了大约2MB的内存(在64位VM上)。在这段时间里,它发出了18000弦。因此,每个String平均使用大约100个字节的内存。
每个字符串的长度在11到17字符之间。由于StringBuilder的分配策略,后者(大约一半)实际上使用32 char数组,前者使用16 char数组。这些需要64或32个字节+数组-开销(至少多12个字节,更可能更多)。此外,String对象本身占用了一些内存开销(至少8+8+4+4+4 = 28用于类和我记得的字段,更可能更多),因此我们平均每个字符串有88个字节。此外,ObjectOutputStream中可能存在一些开销,用于在某些数据结构中维护这些对象。
因此,损失并不比实际需要的多。
啊,关于如何避免存储对象的reset (以及相应的ObjectInputStream )的一个技巧,如果您不打算再次发送对象:每隔几千个字符串调用一次方法.。
在我结束这个程序之前,在一个多小时之后,这里是最后一张截图:

作为比较,我添加了命名的reset并让程序多运行两个小时(还有一点):

它仍然像以前一样收集内存,但现在,当我单击“执行GC”时,它将清除所有内容并回到以前的状态(略高于1MB)。(在堆尾的时候,它也会这样做,但我不想等这么久。)
发布于 2011-02-25 21:09:37
当一个变量实际上超出了作用域时,垃圾收集器就不会运行,否则您将花费大部分时间在GC代码中。
相反,它所做的(这是一个相当简单的)是,它等待您使用的内存达到阈值,然后它才开始释放内存。
这就是你所看到的,你的内存消耗增长得太慢了,需要很长时间才能达到下一个阈值,并真正释放内存。
发布于 2011-02-25 21:13:20
我不认为增加关闭是你的问题,因为我认为你想要做的是继续写到溪流。你试过out.flush()吗?这会刷新内容,使其不再存在于内存中。
https://stackoverflow.com/questions/5122569
复制相似问题