Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/330.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 如何在不浪费内存的情况下在循环中创建对象?_Java_Garbage Collection - Fatal编程技术网

Java 如何在不浪费内存的情况下在循环中创建对象?

Java 如何在不浪费内存的情况下在循环中创建对象?,java,garbage-collection,Java,Garbage Collection,我已经做了一个Java测试程序,看看在循环中使用“new”时Java的行为,结果非常糟糕。以下是节目: package test; public class Test { static int objectCount = 0; public static int getObjectCount() { return objectCount; } public Test() { objectCount++; }

我已经做了一个Java测试程序,看看在循环中使用“new”时Java的行为,结果非常糟糕。以下是节目:

package test;

public class Test {
    static int objectCount = 0;

    public static int getObjectCount() {
        return objectCount;
    }

    public Test() {
        objectCount++;
    }

    public void finalize() {
        objectCount--;
    }


    public static void main(String[] args) {
        int maxObjects = 0;
        long maxMemory = 0;
        long maxUsedMemory = 0;
        long maxFreeMemory = 0;
        long memory = 0;
        long usedMemory = 0;
        long freeMemory = 0;

        final long t0 = System.currentTimeMillis();
        Test test = null;
        for (int i=0; i<10000000; i++) {
            System.gc();
            test = new Test();

            memory = Runtime.getRuntime().totalMemory();
            freeMemory = Runtime.getRuntime().freeMemory();
            usedMemory = memory - freeMemory;

            if (maxMemory < memory) maxMemory = memory;
            if (maxFreeMemory < freeMemory) maxFreeMemory = freeMemory;
            if (maxUsedMemory < usedMemory) maxUsedMemory = usedMemory;

            if (maxObjects < getObjectCount()) maxObjects = getObjectCount();
        }
        final long t1 = System.currentTimeMillis(); 

        System.out.println(
            "Maximum number of objects simultaneously allocated: "+ maxObjects);
        System.out.println("Max memory: " + maxMemory/1024/1024 + "MB");
        System.out.println("Max used memory: " + maxUsedMemory/1024/1024 +"MB");
        System.out.println("Max free memory: " + maxFreeMemory/1024/1024 +"MB");
        System.out.println("Total Time: " + (t1 - t0)/60 + " secconds");
    }
}
测试2:“System.gc();”注释:

Maximum number of objects simultaneously allocated: 0
Max memory: 123MB
Max used memory: 0MB
Max free memory: 122MB
Total Time: 17 secconds
Maximum number of objects simultaneously allocated: 8196834
Max memory: 696MB
Max used memory: 485MB
Max free memory: 343MB
Total Time: 163 secconds
测试3:没有任何注释,总迭代次数降低到10000次(从10000000次):

我相信这是非常充分的,那么,这应该如何添加?有没有办法防止这种情况

更新:

测试2,带-Xmx64M:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at test.Test.main(test.java:31)
同样的结果是128MB

测试2,带-Xmx256M:

(working...) (More than 21 minutes...)

如果创建对象,则会分配一些空间。 如果创建1000个对象,则会分配1000*x的空间


没有办法最小化对象的空间,解决方案是创建更少的对象或等待垃圾回收。

如果创建对象,则会分配一些空间。 如果创建1000个对象,则会分配1000*x的空间


没有办法最小化对象的空间,解决方案是创建更少的对象或等待垃圾回收。

编辑去掉所有代码,这只会使JITs作业更难,并使用以下程序运行
verbose:gc-Xmx8m

public class Test {
    public static void main(String[] args) {
        final long t0 = System.currentTimeMillis();
        for (int i = 0; i < 100 * 10000000; i++) {
            Test test = new Test();
        }
        final long t1 = System.currentTimeMillis();
        System.out.println("Total Time: " + (t1 - t0) / 1000.0 + " secconds");
    }
}
注意:这是迭代计数的100倍

如何在不浪费内存的情况下在循环中创建对象

你不仅仅是在浪费记忆,你是在浪费工作。注意:System.gc()比创建对象要贵很多数量级


如果要优化循环,请在循环外部创建对象。然而,99%的情况下,您不需要这样做,事实上JIT有转义分析,它将对象的字段放在堆栈上,并完全消除对象

试着用
-verbose:gc-Xmx32m
运行它,它会创建足够的对象来填充整个堆1000x,但是

public class EscapeAnalysisMain {
    public static void main(String[] args) {
        int i;
        for (i = 0; i < 2_000_000_000; i++) {
            Integer x = i;
            if (x.hashCode() < 0)
                throw new AssertionError();
        }
        System.out.println(i);
    }
}

i、 e.20亿个
Integer
对象,但没有足够的垃圾使一次收集失败。这怎么可能?代码预热后,
Integer
对象都放在堆栈上,而不是堆上,因此在此之后没有垃圾(最后一行除外)

编辑去掉所有代码,这只会使JITs作业更难,并使用下面的程序运行
verbose:gc-Xmx8m

public class Test {
    public static void main(String[] args) {
        final long t0 = System.currentTimeMillis();
        for (int i = 0; i < 100 * 10000000; i++) {
            Test test = new Test();
        }
        final long t1 = System.currentTimeMillis();
        System.out.println("Total Time: " + (t1 - t0) / 1000.0 + " secconds");
    }
}
注意:这是迭代计数的100倍

如何在不浪费内存的情况下在循环中创建对象

你不仅仅是在浪费记忆,你是在浪费工作。注意:System.gc()比创建对象要贵很多数量级


如果要优化循环,请在循环外部创建对象。然而,99%的情况下,您不需要这样做,事实上JIT有转义分析,它将对象的字段放在堆栈上,并完全消除对象

试着用
-verbose:gc-Xmx32m
运行它,它会创建足够的对象来填充整个堆1000x,但是

public class EscapeAnalysisMain {
    public static void main(String[] args) {
        int i;
        for (i = 0; i < 2_000_000_000; i++) {
            Integer x = i;
            if (x.hashCode() < 0)
                throw new AssertionError();
        }
        System.out.println(i);
    }
}

i、 e.20亿个
Integer
对象,但没有足够的垃圾使一次收集失败。这怎么可能?
Integer
对象在代码预热后都放在堆栈上,而不是堆上,因此在此之后没有垃圾(最后一行除外)

作为一名新开发人员,您正在浪费时间,试图通过Java的自动内存处理和垃圾收集来考虑内存。它工作得很好,专注于编写一些有趣的软件,当它变得相关时,更担心内存管理。是什么让你认为这很糟糕?基于什么研究?您的测试只是表明调用
System.gc()
很慢,这就是为什么您不应该调用它的原因。@JotaGe您的期望是错误的。您希望Java消耗尽可能少的内存。这不是Java优化的目的。Java经过优化,可以在空闲时使用您授权它使用的内存,并在需要时释放它,而不会中断程序太长时间。启动一个有4GB堆空间的JVM,看到它运行得非常慢,因为它总是试图将内存使用率保持在128MB以下,这不是很愚蠢吗?调用gc()会适得其反:您要求Java暂停执行并释放内存,尽管有大量内存可用,但可以在循环之后释放内存,当系统空闲时。作为一名新开发人员,你在浪费时间,试图通过Java的自动内存处理和垃圾收集来考虑内存。它工作得很好,专注于编写一些有趣的软件,当它变得相关时,更担心内存管理。是什么让你认为这很糟糕?基于什么研究?您的测试只是表明调用
System.gc()
很慢,这就是为什么您不应该调用它的原因。@JotaGe您的期望是错误的。您希望Java消耗尽可能少的内存。这不是Java优化的目的。Java经过优化,可以在空闲时使用您授权它使用的内存,并在需要时释放它,而不会中断程序太长时间。启动一个有4GB堆空间的JVM,看到它运行得非常慢,因为它总是试图将内存使用率保持在128MB以下,这不是很愚蠢吗?调用gc()会适得其反:您要求Java暂停执行并释放内存,尽管有大量内存可用,但可以在循环之后释放内存,当系统空闲时。“如果要优化循环,请在外部创建对象”->我的问题是关于必须在循环内部创建的对象。@JotaGe它们不必像人们想象的那样频繁创建。即使对象在循环中,也不意味着它将在堆上创建,它可能在堆栈上。如果创建了heap对象,这不会像人们通常认为的那样影响性能,因为它是一个非常短暂的对象。示例中的大部分性能差异都是由于您正在做的其他事情,如使用<
2000000000