Java 中对象实例的上限

Cap for Object instances in Java

我正在试验对象实例,因为我想查明单个 Java 进程是否定义了最大数量的对象实例。所以我简单地创建了一个对象,它从构造函数中递归地调用自己,如下所示:

public class A{

    private A a;

    public A(){
        a = new A();
    }
}

和一个主要 class 像这样:

public class random {
    public static void main(String[] args) {
        A a = new A();
    }
}

这显然导致了堆栈溢出异常。谷歌搜索后,我发现每个 Java 线程都有自己的堆栈。那么,为什么不在我原来的线程溢出之前生成一个新线程呢?所以我写了这个:

public class A{

    private A a;
    private B b;

    public A(int i, int lim){
        if (i < lim)
            a = new A(i + 1, lim, bufferedWriter);
        else{
            t = new Thread(b = new B(lim));
            t.start();
        }
    }
}

像这样 运行nable:

public class B implements Runnable {

    private int lim;
    private A a;

    public B(int lim) {
        this.lim = lim;
    }

    @Override
    public void run() {
        a = new A(lim, lim + 2500);
    }
}

我怀疑它会再次抛出异常或由于 RAM 不足而崩溃(这就是为什么我让我的任务管理器保持打开状态,准备终止进程)。几分钟后,我很惊讶地发现 RAM 使用情况没有明显变化,我也没有发现任何异常。所以我在eclipse中检查了我的运行配置,它也没有改变并设置为默认值。

为了进一步了解这个主题,我决定开始计算实例。第一次尝试使用简单的“System.out.println”是行不通的,因为 system.out-stream 运行 所在的线程会简单地溢出。所以我决定将计数写入文件,每个线程一个文件。

我的 classes 现在看起来像这样:

主要:

public class random {

    public static void main(String[] args) {
        try {
            A a = new A(0, 2500, new BufferedWriter(new FileWriter(new File(0 + " - " + 2500))));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

甲:

public class A {

    private A a;
    private Thread t;
    private B b;

    public A(int i, int lim, BufferedWriter bufferedWriter) {
        try {
            bufferedWriter.write(i + "\n");
            bufferedWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (i < lim)
            a = new A(i + 1, lim, bufferedWriter);
        else{
            t = new Thread(b = new B(lim));
            t.start();
            try {
                bufferedWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

乙:

public class B implements Runnable {

    private int lim;
    private A a

    public B(int lim) {
        this.lim = lim;
    }

    @Override
    public void run() {
        try {
            a = new A(lim, lim + 2500, new BufferedWriter(new FileWriter(new File(lim + " - " + (lim + 2500)))));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

同样,令人惊讶的是我的 RAM 使用率非常稳定。我更担心我的磁盘存储,因为大约 2 分钟后我的小程序创建了超过 6500 个文件(所以每秒约 33 个文件),每个文件中恰好有 2500 个数字(我想......我没有计算)总数达到 16.260.000。 Ofc 它不足以填满我的磁盘,但我当时停止了它。

好的,如果你读到这里,你要么对我的小实验很感兴趣,要么真的想回答我的问题……所以这里是:

我从未设置任何对 null 的引用,我创建的任何实例都被我的主 class 间接引用。所以我认为垃圾收集器不会触及我宝贵的实例(对吧?)。我的 RAM 怎么没有完全填满?或者至少 JVM 如何没有达到其分配的 RAM 限制?如果我相信我的计数器我有超过 1600 万个对象实例,甚至不计算 B 的实例,并且如果我允许的话,它会每秒创建 83.000 个以上的对象引用 继续。

此外,当我们讨论这个问题时:一个简单的对象会占用多少 RAM?我知道它显然与对象中引用和使用的变量和数量有关,但我们只说一个完全空的对象。它会使用多少内存?

PS:我知道我可以通过在我的主 class 中同时启动线程来加速我的程序,但我的(主要)意图不是用完我所有的磁盘 space 尽可能快,但要计算对象实例:)

我认为你的测试的问题是你的对象仍然被垃圾收集。如果您创建一个线程并且在它完成工作(写入文件)后不保留对它的引用,则它不再被引用并且 java 足够聪明来处理内存。

因此,为了使您的示例按预期工作,您需要保持对线程的引用。例如:

class MainClass {
    public static void main(String[] args) {
        List<B> objects=new ArrayList<>();
            while(true){
             objects.add(new B());
            }
        }
}       

class B implements Runnable {           
    @Override
    public void run() {         
        //do nothing
    }
}

理论上对象创建没有限制。实际上,根据堆大小存在限制。堆是JVM分配的内存区域,用来存放对象。这就是为什么当您的程序用完内存(堆)时,您会面临 OutOfMemoryError。