Java使用的内存多于分配的内存

时间:2014-03-14 02:54:17

标签: java multithreading memory synchronization stack-overflow

我今天早上用Java测试了一些东西,我运行了这段代码,期待aN OutOfMemoryError

public class SynchronizedSpammer {
    public static void main(String[] args) {
        while (true) {
            new Thread(new Runnable() {
                public void run() {
                    syncWait();
                }
            }).start();
        }
    }

    public static synchronized void syncWait() {
        try {
            Thread.sleep(100000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

令我惊讶的是,我的计算机耗尽了所有内存和交换后几秒钟就崩溃了。

这也有效:

public class Crash {
    public static void main(String[] args) {
        while (true) {
            new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(10000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

发生了什么事?为什么内存不受Xmx的限制?

3 个答案:

答案 0 :(得分:3)

您创建了太多Thread个对象!

while (true) {
   new Thread(new Runnable() {
        public void run() {
            syncWait();
        }
    }).start();
}

你是说这个吗?

new Thread(new Runnable() {
    public void run() {
        while (true) {
            syncWait();
        }
    }
}).start();

答案 1 :(得分:1)

在用完堆栈空间之前,你的堆空间会用完。

这里的问题是你正在创建和启动很多线程。所有线程都在syncWait()调用时阻塞,但直到它们到达那里,线程调度程序才忙于上下文切换。除了无限while循环之外,还会重载CPU。

这不是一个记忆问题,尽管它会如何结束。

这里有一些相关的阅读:

答案 2 :(得分:0)

如果线程的堆栈已满(太多局部变量或函数调用),

StackOverflowError将被抛出。

你的线程没有做太多,所以他们没有填满他们的筹码,所以你没有得到StackOverflowError。你的内存不足,因为你创建的线程太多而且每个线程都占用了一些内存(它需要内存用于它的堆栈)。

如果你真的想得到StackOverflowError你可以做的是设置-Xss 104k(104千字节堆栈大小)和:

public class StackEater{
    public static void main(String[] args) throws Exception {

    Thread t = new Thread(new Runnable() {
                   public void run() {
                      printLevel(1);
                   }});
    t.start();
    t.join()
    }

    public static void printLevel(long n) {

        System.out.println(n);
        printLevel(n+1);

    }
}

将最大数字与:

进行比较
public class StackEater{
    public static void main(String[] args) throws Exception {

        Thread t = new Thread(new Runnable() {
                   public void run() {
                      printLevel(1, 1);
                   }});
        t.start();
        t.join()
    }

    public static void printLevel(long n, long m) {

        System.out.println(n);
        printLevel(n+1, m+1);

    }
}

你会看到第二个例子会在抛出异常之前打印出较小的n,因为它通过引入额外的参数来使用更多的堆栈空间。