首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么Java不断地消耗更多的内存?

为什么Java不断地消耗更多的内存?
EN

Stack Overflow用户
提问于 2011-02-25 20:59:11
回答 7查看 4.7K关注 0票数 1

所以我有一个小客户端代码

代码语言:javascript
复制
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”变量吗?

代码语言:javascript
复制
try {
    if (socket == null) {
        final Socket tmp = new Socket("localhost", 1234);
        if (tmp != null) {
           socket = tmp;
        }
        Thread.sleep(100);
    }
} catch (final Exception e) {       
}
EN

回答 7

Stack Overflow用户

发布于 2011-02-25 22:05:29

因此,我已经为您的客户机编写了一个简单的测试服务器,现在我正在运行这两个测试服务器,而且内存使用量似乎没有增加。

代码语言:javascript
复制
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 (因此更快)。现在没问题。

这里有一个变体程序,我没有总是发送相同的字符串,而是每次发送一个不同的字符串:

代码语言:javascript
复制
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)。(在堆尾的时候,它也会这样做,但我不想等这么久。)

票数 8
EN

Stack Overflow用户

发布于 2011-02-25 21:09:37

当一个变量实际上超出了作用域时,垃圾收集器就不会运行,否则您将花费大部分时间在GC代码中。

相反,它所做的(这是一个相当简单的)是,它等待您使用的内存达到阈值,然后它才开始释放内存。

这就是你所看到的,你的内存消耗增长得太慢了,需要很长时间才能达到下一个阈值,并真正释放内存。

票数 2
EN

Stack Overflow用户

发布于 2011-02-25 21:13:20

我不认为增加关闭是你的问题,因为我认为你想要做的是继续写到溪流。你试过out.flush()吗?这会刷新内容,使其不再存在于内存中。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5122569

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档