Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java GC花费太多时间_Java_Garbage Collection_Jvm - Fatal编程技术网

Java GC花费太多时间

Java GC花费太多时间,java,garbage-collection,jvm,Java,Garbage Collection,Jvm,我正在用IntelliJ对Java堆进行一些测试,我得到以下错误: java.lang.OutOfMemoryError: GC overhead limit exceeded. 我知道当GC花费太多时间时会发生这种情况,但我不明白为什么GC会如此频繁地发生并花费这么多时间 设计: -Xms5m -Xmx5m import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Condition;

我正在用IntelliJ对Java堆进行一些测试,我得到以下错误:

java.lang.OutOfMemoryError: GC overhead limit exceeded.
我知道当GC花费太多时间时会发生这种情况,但我不明白为什么GC会如此频繁地发生并花费这么多时间

设计:

-Xms5m -Xmx5m
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Example {

    public static ReentrantLock lock = new ReentrantLock(true);
    public static Condition writeCondition = lock.newCondition();
    public static Condition monitorCondition = lock.newCondition();

    public static void main(String[] args) throws Exception {
        new Thread(new Monitor(lock, writeCondition, monitorCondition)).start(); // start a monitor thread
        Map<Integer, Object> map = new HashMap<>();
        for (int count = 0; count < 10000000; count++) {
            lock.lock();
            try {
                // every time create a new Object, I will use monitor thread print current free heap size
                monitorCondition.signal();
                map.put(count, new Object());
                writeCondition.await();
            } finally {
                lock.unlock();
            }
        }
        for (Map.Entry entry : map.entrySet()) {
            // keep reference to these Objects, so they will not be garbage collected.
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
    }
}

class Monitor implements Runnable {

    ReentrantLock lock;
    Condition writeCondition;
    Condition monitorCondition;

    public Monitor(ReentrantLock lock, Condition writeCondition, Condition monitorCondition) {
        this.lock = lock;
        this.writeCondition = writeCondition;
        this.monitorCondition = monitorCondition;
    }

    @Override
    public void run() {
        int count = 0;
        while (true) {
            lock.lock();
            try {
                writeCondition.signal();
                long heapFreeSize = Runtime.getRuntime().freeMemory();
                System.out.println(count + "  times run monitor : ");
                System.out.println("heapFreesize : " + heapFreeSize);
                System.out.println();
                count++;
                monitorCondition.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}
60005  times run monitor :
heapFreesize:603896
Exception in thread "Thread-0" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.nio.CharBuffer.wrap(CharBuffer.java:373)
    at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
    at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
    at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
    at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
    at java.io.PrintStream.newLine(PrintStream.java:545)
    at java.io.PrintStream.println(PrintStream.java:696)
    at hello.Monitor.run(Example.java:58)
    at java.lang.Thread.run(Thread.java:748)
在主线程中,我重复创建新对象,然后将它们放在地图中。为了防止收集这些对象,我将在将所有对象放入地图后打印这些对象

在监视器线程中,每次创建新对象时,我都打印当前的空闲堆大小

运行时堆大小配置:

-Xms5m -Xmx5m
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Example {

    public static ReentrantLock lock = new ReentrantLock(true);
    public static Condition writeCondition = lock.newCondition();
    public static Condition monitorCondition = lock.newCondition();

    public static void main(String[] args) throws Exception {
        new Thread(new Monitor(lock, writeCondition, monitorCondition)).start(); // start a monitor thread
        Map<Integer, Object> map = new HashMap<>();
        for (int count = 0; count < 10000000; count++) {
            lock.lock();
            try {
                // every time create a new Object, I will use monitor thread print current free heap size
                monitorCondition.signal();
                map.put(count, new Object());
                writeCondition.await();
            } finally {
                lock.unlock();
            }
        }
        for (Map.Entry entry : map.entrySet()) {
            // keep reference to these Objects, so they will not be garbage collected.
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
    }
}

class Monitor implements Runnable {

    ReentrantLock lock;
    Condition writeCondition;
    Condition monitorCondition;

    public Monitor(ReentrantLock lock, Condition writeCondition, Condition monitorCondition) {
        this.lock = lock;
        this.writeCondition = writeCondition;
        this.monitorCondition = monitorCondition;
    }

    @Override
    public void run() {
        int count = 0;
        while (true) {
            lock.lock();
            try {
                writeCondition.signal();
                long heapFreeSize = Runtime.getRuntime().freeMemory();
                System.out.println(count + "  times run monitor : ");
                System.out.println("heapFreesize : " + heapFreeSize);
                System.out.println();
                count++;
                monitorCondition.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}
60005  times run monitor :
heapFreesize:603896
Exception in thread "Thread-0" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.nio.CharBuffer.wrap(CharBuffer.java:373)
    at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
    at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
    at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
    at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
    at java.io.PrintStream.newLine(PrintStream.java:545)
    at java.io.PrintStream.println(PrintStream.java:696)
    at hello.Monitor.run(Example.java:58)
    at java.lang.Thread.run(Thread.java:748)
测试代码:

-Xms5m -Xmx5m
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Example {

    public static ReentrantLock lock = new ReentrantLock(true);
    public static Condition writeCondition = lock.newCondition();
    public static Condition monitorCondition = lock.newCondition();

    public static void main(String[] args) throws Exception {
        new Thread(new Monitor(lock, writeCondition, monitorCondition)).start(); // start a monitor thread
        Map<Integer, Object> map = new HashMap<>();
        for (int count = 0; count < 10000000; count++) {
            lock.lock();
            try {
                // every time create a new Object, I will use monitor thread print current free heap size
                monitorCondition.signal();
                map.put(count, new Object());
                writeCondition.await();
            } finally {
                lock.unlock();
            }
        }
        for (Map.Entry entry : map.entrySet()) {
            // keep reference to these Objects, so they will not be garbage collected.
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
    }
}

class Monitor implements Runnable {

    ReentrantLock lock;
    Condition writeCondition;
    Condition monitorCondition;

    public Monitor(ReentrantLock lock, Condition writeCondition, Condition monitorCondition) {
        this.lock = lock;
        this.writeCondition = writeCondition;
        this.monitorCondition = monitorCondition;
    }

    @Override
    public void run() {
        int count = 0;
        while (true) {
            lock.lock();
            try {
                writeCondition.signal();
                long heapFreeSize = Runtime.getRuntime().freeMemory();
                System.out.println(count + "  times run monitor : ");
                System.out.println("heapFreesize : " + heapFreeSize);
                System.out.println();
                count++;
                monitorCondition.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}
60005  times run monitor :
heapFreesize:603896
Exception in thread "Thread-0" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.nio.CharBuffer.wrap(CharBuffer.java:373)
    at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
    at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
    at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
    at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
    at java.io.PrintStream.newLine(PrintStream.java:545)
    at java.io.PrintStream.println(PrintStream.java:696)
    at hello.Monitor.run(Example.java:58)
    at java.lang.Thread.run(Thread.java:748)

当可用内存不足时,GC会通过在堆中收集无法访问的对象来释放一些内存。检查对象是否无法访问不是一项容易的任务,需要一些时间


当您的所有(或大部分)对象仍在某个位置被引用时,这是浪费时间,因为没有回收内存。因此,当JVM意识到大量的运行时花费在运行GC而不是做一些有用的事情时,程序会在您指定的
-Xms5m-Xmx5m
参数
JVM
中以
OutOfMemoryError

终止,因此堆大小设置为
5MB
,即
5242880字节
。现在,由于您已经执行了
10000000
次循环,因此您正在
Map
中分配
10000000
类型为
Integer
Object
对象。现在,如果您查看功能,您将意识到您在
map
中为单个条目平均提供了
0.524288
字节。但正如您所知,
Integer
对象的大小大于
4字节
(因为
int
的大小是
4字节
Integer
包装
int
类型)

因此,简而言之,您没有为
JVM
堆分配足够的内存,这就是您获得异常的原因。
java.lang.OutOfMemoryError:超出了GC开销限制。

注意:查看程序的以下输出后,我意识到单个条目占用了
848字节的内存(请参见下面的计算)。因此,您将需要至少
10000000*848=848000000字节
,即
8088 MB
内存(物理或虚拟内存):

尝试将更多的堆分配给
JVM
,将不会出现此错误。有关Java HotSpot VM选项的更多信息,请参见和

计算:在提供的输出(我在上面发布)中,正在打印可用内存。现在,如果您进行计算,您将发现在向映射添加一个条目后,内存之间的差异是
848
。因此,我可以说,
map
中的单个条目(不是单个对象,因为有两个对象-整数类和对象类)正在消耗
848 byres
,例如
32344-31496=848
<代码>31496-30648=848
<代码>30648-29800=848,依此类推

还请注意,如果您没有使用相同的值设置
-Xms
-Xmx
开关(因为我在执行示例运行时没有使用这些开关),那么
JVM
将根据需要增加或减少堆大小


注意:由于使用了
writeCondition.signal(),您的代码在逻辑上似乎不正确
监视器条件.await()不在
sync
中。程序正在无限地等待
。我认为它在最后被卡住了。

在这段代码中,您试图将1000万个对象(通常每个8字节)放入5Mb堆中(甚至不计算运行时和您使用的其他元素的开销)。这是行不通的。@gpeche是的,事实上我希望
OutOfMemoryError
。但我不明白GC为什么要花这么多时间。因为我创建的对象不应该被垃圾收集。有趣的阅读:@user6690200 read,它引用的JVM似乎不够聪明,无法快速找到我创建的所有对象,它只是重复检查这些对象。我说得对吗?是的,这是正确的。然而,这个问题本身就很难解决;所以这不是一个不够聪明的问题。@user6690200“JVM不够聪明”是什么意思?您将使用新创建的对象填充贴图,直到内存已满。这与聪明无关。没有要收集的对象。@Holger我的意思是,JVM在查找无法访问的对象上花费的时间太多了吗。事实上,没有不可访问的对象。@Holger和,抛出OutOfMemoryError时,似乎仍有可用的堆空间,我希望在没有可用的堆空间之前不会抛出此错误……谢谢。我将循环更改为60000,这足够小,可以分配到5MB空间。我仍然会犯同样的错误。有什么方法可以降低GC所用时间的限制吗?@user6690200对于
map
变量中的
60000
条目,您至少需要
48.6MB
内存。因此,我建议将
JVM
参数设置为
-Xms60m-Xmx60m
。请注意,48.6 MB是
map
保存条目所需的内存。
JVM
将需要更多的内存来执行它的其他任务。非常感谢!我发现当使用60000和5MB堆大小时,测试结果可能会有所不同,有时所有60000个条目都可以放入map,有时失败。请问,为什么你说单个对象需要
848
字节?@user6690200在提供的输出中(由我在回答中发布),可用内存正在打印。现在,如果您进行计算,您将发现在
map
中添加一个条目后,内存之间的差异是
848
。因此,我可以说,单个条目(不是单个对象,因为有2个