所以,我已经为您的客户端编写了一个简单的测试服务器,现在我正在运行这两个测试服务器,并且似乎没有增加内存使用量。
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毫秒我派遣一个对象,记不清了),而...
我们可以看到,内存使用有看到了牙齿曲线 - 它逐渐增加,然后出现垃圾收集,并且正在跌落到基本usag即经过一段初始阶段后,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仍然占据着我们的字符串引用...
在半小时我们的节目吃大约2 MB的内存(在64位VM上)。在这个时候,它发送了18000个字符串。所以,每个字符串平均使用大约100个字节的内存。
这些字符串中的每一个都在11到17个字符之间。后者(大约一半)实际上使用32字符数组,前者是16字符数组,因为StringBuilder的分配策略。这些需要64或32字节+数组开销(至少多12个字节,更可能更多)。此外,String对象本身需要一些内存开销(对于类和我记忆的字段,至少8 + 8 + 4 + 4 + 4 = 28,更可能更多),所以每个字符串平均具有(至少)88个字节。此外,在ObjectOutputStream中可能会有一些开销来维护这些对象的某些数据结构。
所以,没有比实际需要更多的损失。
啊,如何避免用ObjectOutputStream一个尖端(以及相应的ObjectInputStream的,太)存储的对象,如果你不发送任何人再次计划:调用它reset
方法每天几千串左右。
这里是最后的截图之前,我杀程序,经过一个多小时了一下:
为了便于比较,我加入了一个名为reset
,让程序运行两小时(和位):
它作为前仍会收集记忆,但现在当我点击“执行GC”可以清理一切,去BAC k在之前的状态(仅略高于1 MB)。 (在堆结束时它会这样做,但我不想等这么久。)
在强制gc后会发生什么?请记住,内存可能会以10kb的增量进行分配,但除非实际发生泄漏,否则它将全部收集起来,然后在分配新内存之前将其恢复为原始使用(或大约)。 – 2011-02-25 21:01:10
如果你让它运行足够长时间,你会得到一个OutOfMemoryError? – Poindexter 2011-02-25 21:02:14
你是不是应该关闭socket? – Alexandru 2011-02-25 21:04:17