Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.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 使用ObjectInputStream#readUnshared()时出现意外的OutOfMemoryError_Java_Out Of Memory_Deserialization_Objectinputstream - Fatal编程技术网

Java 使用ObjectInputStream#readUnshared()时出现意外的OutOfMemoryError

Java 使用ObjectInputStream#readUnshared()时出现意外的OutOfMemoryError,java,out-of-memory,deserialization,objectinputstream,Java,Out Of Memory,Deserialization,Objectinputstream,当使用readUnshared从ObjectInputStream读取大量对象时,我遇到了OOM。指向其内部句柄表作为罪魁祸首,OOM堆栈跟踪也是如此(在本文末尾)。据所有人说,这不应该发生。此外,OOM是否发生似乎取决于之前如何写入对象 根据,readUnshared应该通过在读取过程中不创建句柄表条目来解决这个问题(与readObject相反)(这就是我发现writeUnshared和readUnshared的原因,我以前没有注意到) 然而,从我自己的观察来看,readObject和read

当使用
readUnshared
ObjectInputStream
读取大量对象时,我遇到了OOM。指向其内部句柄表作为罪魁祸首,OOM堆栈跟踪也是如此(在本文末尾)。据所有人说,这不应该发生。此外,OOM是否发生似乎取决于之前如何写入对象

根据,
readUnshared
应该通过在读取过程中不创建句柄表条目来解决这个问题(与
readObject
相反)(这就是我发现
writeUnshared
readUnshared
的原因,我以前没有注意到)

然而,从我自己的观察来看,
readObject
readUnshared
的行为相同,OOM是否发生取决于对象是否使用(如果使用了
writeObject
vs
writeUnshared
,这并不重要,正如我之前所想的那样——我只是在第一次运行测试时感到疲劳而已)。也就是说:

writeObject writeObject+reset writeUnshared writeUnshared+reset readObject OOM OK OOM OK readUnshared OOM OK OOM OK 使用该程序重新创建问题的步骤:

  • 在堆大小设置为高的情况下运行测试程序,使
    testWrite
    s未注释(并且
    testRead
    未调用),这样
    writeObject
    不会导致OOM
  • 第二次运行测试程序时,使用默认堆大小
    testRead
    未注释(和
    testWrite
    未调用)
  • 需要明确的是:我没有在同一个JVM实例中进行写和读操作。我的写操作与读操作发生在一个单独的程序中。乍一看,上面的测试程序可能有点误导,因为我将写测试和读测试都塞进了同一个源代码中

    不幸的是,我所处的实际情况是,我有一个包含大量对象的文件,这些对象是用
    writeObject
    编写的(没有
    reset
    ),这将需要相当长的时间才能重新生成(以天为单位)(
    reset
    也会使输出文件变得庞大),因此如果可能的话,我希望避免这种情况。另一方面,我当前无法使用
    readObject
    读取文件,即使堆空间已达到系统上可用的最大值

    值得注意的是,在我的实际情况中,我不需要对象流句柄表提供的缓存

    因此,我的问题是:

  • 到目前为止,我的所有研究都表明,
    readUnshared
    的行为与对象的编写方式之间没有联系。这是怎么回事?
  • 如果数据是用
    writeObject
    写入的,并且没有
    reset
    ,有什么方法可以避免读取时的OOM吗?
  • 我不完全清楚为什么
    readUnshared
    无法解决这里的问题

    我希望这是清楚的。我在这里运行的空白,所以可能输入了奇怪的单词


    根据以下答案:


    如果未在JVM的当前实例中调用
    writeObject()
    ,则不应通过调用
    readUnshared()
    来消耗内存

    我所有的研究都显示了同样的结果,但令人困惑的是:

    • 这是OOM堆栈跟踪,指向
      readUnshared

      Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
      at java.io.ObjectInputStream$HandleTable.grow(ObjectInputStream.java:3464)
      at java.io.ObjectInputStream$HandleTable.assign(ObjectInputStream.java:3271)
      at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1789)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
      at java.io.ObjectInputStream.readUnshared(ObjectInputStream.java:460)
      at OOMTest.testRead(OOMTest.java:40)
      at OOMTest.main(OOMTest.java:54)
      
    • 这是一个(在最近的测试程序编辑之前录制的视频,视频相当于新测试程序中的
      ReadMode.UNSHARED
      WriteMode.NORMAL

    • 以下是包含30000000个对象(压缩大小很小,只有360KB,但请注意,它会扩展到2.34GB)。这里有四个测试文件,每个文件都是通过
      writeObject
      /
      writeUnshared
      reset
      的各种组合生成的。读取行为仅取决于写入方式,与
      readObject
      readUnshared
      无关。请注意
      writeObject
      writeUnshared
      无关数据文件是逐字节相同的,我无法决定这是否令人惊讶


    我一直在盯着
    ObjectInputStream
    代码。我目前的嫌疑犯是,出现在1.7和1.8中:

    ObjectStreamClass desc = readClassDesc(false);
    
    其中,
    boolean
    参数为
    true
    表示非共享,为
    false
    表示正常。在所有其他情况下,“非共享”标志被传播到其他调用,但在这种情况下,它被硬编码为
    false
    ,因此在读取序列化对象的类描述时,即使使用了
    readUnshared
    ,也会导致句柄被添加到句柄表中ds,这就是我关注它的原因

    这与例如unshared标志传递到
    readClassDesc
    的情况相反(如果有人想深入,您可以跟踪从
    readUnshared
    到这两行的调用路径。)

    然而,我还没有证实这其中的任何一个是重要的,也没有解释为什么
    false
    是硬编码的。这只是我正在研究的当前轨迹,它可能被证明是没有意义的

    另外,fwiw,
    ObjectInputStream
    确实有一个私有方法,
    clear
    ,用于清除句柄表。我做了一个实验,在每次读取后调用它(通过反射),但它破坏了一切,所以这是不可能的

    但是,如果对象是使用
    writeObject()
    而不是
    writeUnshared()
    编写的,那么
    readUnshared()
    并不会减少句柄表的使用

    这是正确的。
    readUnshared()
    只会减少可归因于
    readObject()
    的句柄表使用量。如果您所在的JVM使用的是
    writeObject()
    而不是
    writeUnshared()
    ,则可归因于
    writeObject()
    的句柄表使用量不会减少
    readU
    
    ObjectStreamClass desc = readClassDesc(false);