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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12073150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 07:29:10  来源:igfitidea点击:

ByteArrayOutputStream Out of memory error while recording in java sound

java

提问by Mihir

I encountered a very strange problem. I am writing portion of the code below.

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

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 is the TargetDataLine from which I am recording sound in to byteArrayOutputStream. it works normally until 40 - 48 seconds very well in my test , but when it reaches 49 seconds every time it throws an exception below :

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)

I am using this technique because I need the recorded bytes and from those bytes I am drawing a wave form succesfully on the UI.

我使用这种技术是因为我需要记录的字节,并且从这些字节中我成功地在 UI 上绘制了一个波形。

During test I come to know that an exception raised when the size of the byteArrayOutputStream is only 7.3 mb.

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

Can I write this byteArrayOutputStream to random access file and then reset this byteArrayOutputStream everytime it reaches to its limit?

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

How do I know in advance the limits of the byteArrayOutputStream?

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

I checked with Integer.MAX_VALUE but as I said it just raised an exception at 7.3 mb so I can not reach to Integer.MAX_VALUE.

我检查了 Integer.MAX_VALUE,但正如我所说,它只是在 7.3 mb 处引发了一个异常,所以我无法访问 Integer.MAX_VALUE。

This applet runs on the internet, so setting memory size will not help me. How can I set it to my client's computer?

这个小程序运行在互联网上,所以设置内存大小对我没有帮助。如何将其设置到我客户的计算机上?

回答by Stephan

Your problem is, that the JVM is running out of memory because you keep all the data in memory. Extending the heap space helps temporarily until you need to work with even longer audios.

您的问题是,JVM 内存不足,因为您将所有数据保存在内存中。在您需要处理更长的音频之前,扩展堆空间会暂时有所帮助。

One idea might be to exchange the ByteArrayOutputStreamby an FileOutputStreamto a temporary File. This wouldn't require all audio data to be kept in memory. An even nicer solution is GuavasFileBackedOutputStreamwhich stores the data only in a temporary file if it surpasses a certain threshold.

一种想法可能是将ByteArrayOutputStreamby交换FileOutputStream为临时File。这不需要将所有音频数据保存在内存中。一个更好的解决方案是GuavasFileBackedOutputStream,它仅在数据超过某个阈值时将数据存储在一个临时文件中。

Another solution would be to update the waveform directly which each buffer. By creating a method which just receives the buffer with the audio data in it and applying it to the current state of the waveform. This way you wouldn't need to store the audio data at all.

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

回答by Stephen C

This problem occurs because a Hotspot JVM's heap has a fixed upper bound on its size. The default limit depends on your platform, but it could be as low as 40Mb.

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

What you are doing is reading large amounts of data from your audio stream and buffering them in memory. Given that the heap has an upper limit, your application is eventually going to run into that limit, and the result will be an OutOfMemoryErrorexception.

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

The obvious solution is to increase the maximum heap space for the JVM using the -Xmxoption. (Refer to the java command manual entry for more information on this option.) However there is an ultimate limit to how big you can make the JVMs heap ... depending on your hardware, the OS and whether or not you are using a 64 bit JVM.

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

You could also save the audio data to a file or attempt to compress it or reduce it, but these will all make the graphing more complicated.

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

回答by Andrew Thompson

Others have discussed the source of the problem.

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

To solve it, either:

要解决它,要么:

  1. Draw the bytes a little at a time, or..
  2. Store one single BufferedImage, grab the bytes in small chunks, and draw them immediately to the image.
  1. 一次绘制一点字节,或者..
  2. 存储一个 single BufferedImage,将字节分成小块,然后立即将它们绘制到图像上。

The first technique might result in something like seen in this You Tube Video

第一种技术可能会导致在此You Tube Video 中看到的内容

Sound trace

声迹

回答by gkuzmin

You can try to increase JVMheap space or try to compress your sound data to consume less memory.

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

回答by pratikabu

It will definitely fill your memory and its behavior will be different on different computers. What you can do is use some FileOutputStreamand write data onto it and once your loop ends pull data from there and convert it to wav. Also write your data in small packets of bytes (preferably 4096).. ensure your length of tempBufferdoesn't increases more than 4096.

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

Hope this helps..

希望这可以帮助..