ByteArrayOutputStream在java声音录制时出现内存不足错误

时间:2012-08-22 12:27:54

标签: java

我遇到了一个非常奇怪的问题。我正在编写下面代码的一部分。

try {
    while (!stopCapture) {
        // Read data from the internal buffer of the data line.
        int cnt = this.recLine.read(tempBuffer, 0, tempBuffer.length);
        if (cnt > 0) {
            // Save data in output stream object.
            byteArrayOutputStream.write(tempBuffer, 0, cnt);
            // System.out.println(" bytes " + tempBuffer[0]);
        }// end if
    }// ends while

    // AudioSystem.write(myAIS, targetType, outputFile);
    byteToWave(byteArrayOutputStream);
    byteArrayOutputStream.close();
} catch (IOException e) {
    // TODO provide runtime exception to reach it to presentation layer
    e.printStackTrace();
} catch (Exception ex) {
    ex.printStackTrace();
}

recLine是TargetDataLine,我将声音录制到byteArrayOutputStream中。它在我的测试中正常工作直到40-48秒,但是每当它在下面抛出异常时达到49秒:

Exception in thread "Thread-5" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:2786)
    at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:94)
    at com.actura.app.capture.ActuraRecorder.run(ActuraRecorder.java:109)
    at java.lang.Thread.run(Thread.java:619)

我正在使用这种技术,因为我需要记录的字节,从那些字节我在UI上成功绘制波形。

在测试期间,我发现当byteArrayOutputStream的大小仅为7.3 mb时会引发异常。

我可以将此byteArrayOutputStream写入随机访问文件,然后每次达到其限制时重置此byteArrayOutputStream吗?

我如何提前知道byteArrayOutputStream的限制?

我使用Integer.MAX_VALUE进行了检查,但正如我所说,它只是在7.3 mb处引发异常,因此无法达到Integer.MAX_VALUE。

此applet在互联网上运行,因此设置内存大小对我没有帮助。如何将其设置到客户端的计算机上?

5 个答案:

答案 0 :(得分:6)

您的问题是,JVM内存不足,因为您将所有数据保留在内存中。扩展堆空间有助于暂时,直到您需要使用更长的音频。

一个想法可能是将ByteArrayOutputStreamFileOutputStream交换为临时File。这不需要将所有音频数据保存在存储器中。更好的解决方案是Guavas FileBackedOutputStream,如果数据超过某个阈值,它只会将数据存储在临时文件中。

另一种解决方案是直接更新每个缓冲区的波形。通过创建一种方法,该方法仅接收具有音频数据的缓冲器并将其应用于波形的当前状态。这样您根本不需要存储音频数据。

答案 1 :(得分:2)

出现此问题的原因是Hotspot JVM的堆在其大小上具有固定的上限。默认限制取决于您的平台,但可能低至40Mb。

您正在做的是从音频流中读取大量数据并在内存中缓冲它们。鉴于堆具有上限,您的应用程序最终将遇到该限制,结果将是OutOfMemoryError异常。

显而易见的解决方案是使用-Xmx选项增加JVM的最大堆空间。 (有关此选项的更多信息,请参阅java命令手册条目。)但是,对于JVM堆积的大小有一个最终限制...取决于您的硬件,操作系统以及您是否使用64位JVM。

您还可以将音频数据保存到文件中或尝试压缩或减少它,但这些都会使图形更复杂。

答案 2 :(得分:1)

其他人已经讨论过问题的根源。

要解决它,要么:

  1. 一次绘制一些字节,或者..
  2. 存储一个BufferedImage,以小块的形式获取字节,然后立即将它们绘制到图像中。
  3. 第一种技术可能会产生类似于You Tube Video

    的内容

    Sound trace

答案 3 :(得分:0)

您可以尝试增加JVM堆空间或尝试压缩声音数据以减少内存消耗。

答案 4 :(得分:0)

它肯定会填满你的记忆,它的行为在不同的计算机上会有所不同。 您可以做的是使用一些FileOutputStream并将数据写入其中,一旦您的循环结束从那里提取数据并将其转换为wav。 还要用小包字节(最好是4096)写入数据。确保tempBuffer的长度不超过4096。

希望这会有所帮助..