紧密的“循环"中的PipedInputStream/PipedOutputStream::为什么"java.lang.OutOfMemoryError:Java堆空间"? [英] PipedInputStream / PipedOutputStream in a tight "loop" :: Why the "java.lang.OutOfMemoryError: Java heap space"?

查看:66
本文介绍了紧密的“循环"中的PipedInputStream/PipedOutputStream::为什么"java.lang.OutOfMemoryError:Java堆空间"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 PipedInputStream PipedOutputStream ,无法理解以下代码为何会导致Java Heap耗尽问题.创建的所有临时 String 对象都应进行 gc 版本.为什么然后出现 OutOfMemoryError ?

I am experimenting with PipedInputStream and PipedOutputStream and can't understand why the following code would result in a Java Heap exhaustion problem. All transient String objects created should be gc-ed. Why then do I get an OutOfMemoryError ?

我正在尝试读写1000个 String 对象,每个对象的长度为一百万个字符.即使使用 -Xmx2g 进行调用,下面的代码也会中途失败.更重要的是:

I am trying to write and read 1000 String objects each 1 million characters long. The below code fails about half-way through even when invoked with -Xmx2g. What's more the trace:

written string #453
read string #453
written string #454
Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space

...揭示了 PipedInputStream 只是 PipedOutputStream 之后的一个 String 对象.我不明白为什么垃圾回收无法回收所有必需的堆内存.

... reveals that the PipedInputStream is only one String object "behind" the PipedOutputStream. I don't see why garbage collection has failed to reclaim all necessary heap memory.

import java.io.*;
import java.util.*;


class Worker implements Runnable {

    private ObjectOutputStream oos;
    private PipedInputStream   pis;

    public Worker() throws IOException {
        this.pis = new PipedInputStream();
        this.oos = new ObjectOutputStream(new PipedOutputStream( pis ));
    }

    @Override
    public void run() {
        try {
            for (int i = 0 ; i < 1000 ; i++) {
                oos.writeObject(aBigString());
                System.out.printf("written string #%d\n", i);
            }
            oos.flush();
            oos.close();
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    private static String aBigString() {
        StringBuffer sb = new StringBuffer();
        for (int i = 0 ; i < 1000*1000 ; i++)
            sb.append("X");
        return sb.toString();
    }

    public PipedInputStream getInput() {
        return this.pis;
    }
}


public class FooMain {
    public static void main(String args[]) throws IOException, ClassNotFoundException {
        Worker worker = new Worker();
        (new Thread(worker)).start();
        ObjectInputStream ois = new ObjectInputStream(worker.getInput());
        String record = null;
        int i = 0;
        try {
            while (true) {
                record = (String) ois.readObject();
                System.out.printf("read string #%d", i++);
            }
        } catch (EOFException e) {
            ois.close();
            System.out.println("done.");
        }
    }
}

推荐答案

这与Piped流无关.您遇到了对象流的经典陷阱之一.为了保留对象身份,流将保留通过它们的 all 个对象.如果需要将这些流用于大量对象,则需要定期在 ObjectOutputStream 上调用 reset()(但请注意,重置时不会保留对象身份)电话).

This has nothing to do with the Piped streams. you are hitting one of the classic pitfalls of the Object streams. In order to preserve object identity, the streams will hold onto all objects pass through them. If you need to use these streams for a large number of objects, you need to periodically call reset() on the ObjectOutputStream (but beware that object identities are not preserved across reset calls).

这篇关于紧密的“循环"中的PipedInputStream/PipedOutputStream::为什么"java.lang.OutOfMemoryError:Java堆空间"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆