我遇到了一个非常奇怪的问题。我正在编写下面代码的一部分。
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在互联网上运行,因此设置内存大小对我没有帮助。如何将其设置到客户端的计算机上?
答案 0 :(得分:6)
您的问题是,JVM内存不足,因为您将所有数据保留在内存中。扩展堆空间有助于暂时,直到您需要使用更长的音频。
一个想法可能是将ByteArrayOutputStream
与FileOutputStream
交换为临时File
。这不需要将所有音频数据保存在存储器中。更好的解决方案是Guavas FileBackedOutputStream
,如果数据超过某个阈值,它只会将数据存储在临时文件中。
另一种解决方案是直接更新每个缓冲区的波形。通过创建一种方法,该方法仅接收具有音频数据的缓冲器并将其应用于波形的当前状态。这样您根本不需要存储音频数据。
答案 1 :(得分:2)
出现此问题的原因是Hotspot JVM的堆在其大小上具有固定的上限。默认限制取决于您的平台,但可能低至40Mb。
您正在做的是从音频流中读取大量数据并在内存中缓冲它们。鉴于堆具有上限,您的应用程序最终将遇到该限制,结果将是OutOfMemoryError
异常。
显而易见的解决方案是使用-Xmx
选项增加JVM的最大堆空间。 (有关此选项的更多信息,请参阅java命令手册条目。)但是,对于JVM堆积的大小有一个最终限制...取决于您的硬件,操作系统以及您是否使用64位JVM。
您还可以将音频数据保存到文件中或尝试压缩或减少它,但这些都会使图形更复杂。
答案 2 :(得分:1)
其他人已经讨论过问题的根源。
要解决它,要么:
BufferedImage
,以小块的形式获取字节,然后立即将它们绘制到图像中。第一种技术可能会产生类似于You Tube Video
的内容
答案 3 :(得分:0)
您可以尝试增加JVM
堆空间或尝试压缩声音数据以减少内存消耗。
答案 4 :(得分:0)
它肯定会填满你的记忆,它的行为在不同的计算机上会有所不同。
您可以做的是使用一些FileOutputStream
并将数据写入其中,一旦您的循环结束从那里提取数据并将其转换为wav
。
还要用小包字节(最好是4096)写入数据。确保tempBuffer
的长度不超过4096。
希望这会有所帮助..