Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/380.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
PipedInputStream/PipedOutStream处于紧密的“状态”;循环“::为什么会有";java.lang.OutOfMemoryError:java堆空间“;?_Java_Garbage Collection_Heap - Fatal编程技术网

PipedInputStream/PipedOutStream处于紧密的“状态”;循环“::为什么会有";java.lang.OutOfMemoryError:java堆空间“;?

PipedInputStream/PipedOutStream处于紧密的“状态”;循环“::为什么会有";java.lang.OutOfMemoryError:java堆空间“;?,java,garbage-collection,heap,Java,Garbage Collection,Heap,我正在试验PipedInputStream和PipedOutputStream,无法理解为什么下面的代码会导致Java堆耗尽问题。创建的所有瞬态String对象都应gc-ed。那么为什么我会得到OutOfMemoryError 我正在尝试写入和读取1000个String对象,每个对象的长度为100万个字符。即使使用-Xmx2g调用,下面的代码也会在中途失败。更重要的是跟踪: written string #453 read string #453 written string #454 Exce

我正在试验
PipedInputStream
PipedOutputStream
,无法理解为什么下面的代码会导致Java堆耗尽问题。创建的所有瞬态
String
对象都应gc-ed。那么为什么我会得到
OutOfMemoryError

我正在尝试写入和读取1000个
String
对象,每个对象的长度为100万个字符。即使使用
-Xmx2g
调用,下面的代码也会在中途失败。更重要的是跟踪:

written string #453
read string #453
written string #454
Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
。。。显示
pipedOutStream
只是
pipedOutStream
后面的一个
String
对象。我不明白为什么垃圾收集无法回收所有必需的堆内存

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.");
        }
    }
}
import java.io.*;
导入java.util.*;
类工作者实现可运行的{
私有对象输出流oos;
私有管道数据流pis;
公共工作者()抛出异常{
this.pis=新的PipedInputStream();
this.oos=新对象输出流(新管道输出流(pis));
}
@凌驾
公开募捐{
试一试{
对于(int i=0;i<1000;i++){
oos.writeObject(aBigString());
System.out.printf(“写入字符串#%d\n”,i);
}
oos.flush();
oos.close();
}捕获(IOE异常){
抛出新的RuntimeException(例如getMessage());
}
}
私有静态字符串aBigString(){
StringBuffer sb=新的StringBuffer();
对于(int i=0;i<1000*1000;i++)
某人附加(“X”);
使某人返回字符串();
}
公共PipedInputStream getInput(){
返回这个.pis;
}
}
公共类FooMain{
公共静态void main(字符串args[])引发IOException,ClassNotFoundException{
工人=新工人();
(新线程(辅助线程)).start();
ObjectInputStream ois=新的ObjectInputStream(worker.getInput());
字符串记录=null;
int i=0;
试一试{
while(true){
记录=(字符串)ois.readObject();
System.out.printf(“读取字符串#%d”,i++);
}
}捕获(EOFEException e){
ois.close();
System.out.println(“完成”);
}
}
}

这与管道流无关。您遇到了对象流的一个经典陷阱。为了保留对象标识,流将保留通过它们的所有对象。如果需要将这些流用于大量对象,则需要定期调用
ObjectOutputStream
上的
reset()
(但请注意,对象标识不会在重置调用中保留)。

这与管道流无关。您遇到了对象流的一个经典陷阱。为了保留对象标识,流将保留通过它们的所有对象。如果需要将这些流用于大量对象,则需要定期调用
ObjectOutputStream
上的
reset()
(但请注意,对象标识不会在重置调用中保留)。

我建议下载Visual VM,安装所有插件,并在代码执行时将其附加到PID。它将向您显示内存、线程、对象、CPU等等。

我建议下载Visual VM,安装所有插件,并在代码执行时将其附加到PID。它将向您显示内存、线程、对象、CPU以及更多信息。

您是否尝试过StringBuilder而不是StrungBuffer?可能是perm gen填充,这是堆外的。32位JVM可能无法解决所有这些问题。只是想了解一下代码的要点:启动一个线程,用一千一百万的内存填充
PipedInputStream
中的缓冲区。同时对字符进行反序列化的时候?这些字符串需要在内存中多次出现:创建时作为字符串本身,在管道中序列化时作为字节[],读取时作为字符串返回。在最坏的情况下,这可能需要多达6兆。@ThomasJungblut:为什么?它们不是gc-ed吗?@MarcusJuniusBrutus管道的输入字符串将在您
reset()
时收集,但管道的内部缓冲区将在您取消引用时收集-只要它是活动的,它将携带1k字符串的信息(在最坏的情况下).您尝试过StringBuilder而不是StrungBuffer吗?可能是perm gen正在填充,这是堆外的。32位JVM可能无法解决所有这些问题。只是想了解一下代码的要点:启动一个线程,用一千一百万的内存填充
PipedInputStream
中的缓冲区。同时对字符进行反序列化的时候?这些字符串需要在内存中多次出现:创建时作为字符串本身,在管道中序列化时作为字节[],读取时作为字符串返回。在最坏的情况下,这可能需要多达6兆。@ThomasJungblut:为什么?它们不是gc-ed吗?@MarcusJuniusBrutus管道的输入字符串将在您
reset()
时收集,但管道的内部缓冲区将在您取消引用时收集-只要它是活动的,它将携带1k字符串的信息(在最坏的情况下).我只需要了解使用reset()和“不保留对象标识”的后果是什么;但也许这应该是另一个问题。我只需要理解使用reset()和“不保留对象标识”的后果是什么;但也许这应该是另一个问题。