【发布时间】:2020-09-08 02:16:23
【问题描述】:
我正在开发一个Java library,它是Windows Waveform Functions 通过Java 播放24 位音频的薄包装。 (JVM 只支持 8bit 和 16bit 音频)。
Windows 波形函数中的范例是:
- 创建标头结构
- 在 Header 上调用 waveOutPrepareHeader。
- 向声卡发送标头
- 声卡异步播放(这意味着 Header 在音频播放期间必须保留在内存中)
- 声卡播放完毕后,它会在标题中设置一个“完成”位
- 设置“完成”位后,我必须调用
waveOutUnprepareHeader - 然后我可以从内存中删除标题
鉴于我的 Java 库将成为原生波形函数的薄包装器,我有一个用于 Header Pointer 的类,因此我可以根据需要将其保持在范围内,根据需要传递它,并且最终调用waveOutUnprepareHeader就可以了。
public class WaveHeader {
long waveHeaderPointer;
public WaveHeader(byte[] buffer) {
waveHeaderPointer = HWaveOut.createHeader(buffer, buffer.length);
}
}
上面第 5 行调用的本机代码 (HWaveOut.createHeader()) 是:
JNIEXPORT jlong JNICALL Java_net_joshuad_waveformjni_HWaveOut_createHeader
(JNIEnv * env, jclass jclass, jbyteArray jbuffer, jint jBufferSize) {
char* buffer = new char[jBufferSize];
asCharArray(env, jbuffer, buffer);
WAVEHDR* headerOut = new WAVEHDR{ buffer, (DWORD)jBufferSize, 0, 0, 0, 0, 0, 0 };
std::cout << "[C++] Header out location: " << headerOut << std::endl;
return (jlong)headerOut;
}
如您所见,我在 C++ 的堆上分配了一个 WAVEHDR。
我的理解是,当我完成 WAVEHDR 后,我负责解除分配 - Java 垃圾收集器不会为我销毁它。
我最初考虑将解除分配代码放在java中的finalize()中,这样当java对象在java中被垃圾回收时,C++结构总是会自动解除分配,但是根据this answer这个方法会导致内存泄漏。
然后我想在 InputStream 之类的类中对未关闭的资源使用编译器警告来捕捉我犯的任何错误,但即使我犯了 WaveHeader Closable,我也没有收到编译器警告我'如果我不打电话给close(),我已经习惯了。
有什么好的方法可以保护自己免受意外的内存泄漏吗?
【问题讨论】:
-
我的理解是,当我完成 WAVEHDR 后,我负责解除分配 -- 无论您是否使用 Java,情况都是如此。如果这纯粹是一个 C++ 应用程序,你将如何处理?
-
我有一个可以正常工作的 C++ 解决方案。我可以用 Java 编写那个确切的解决方案,我可以立即设计。我在问Java中是否有一些机制可以用来帮助避免程序员的错误,因为Java程序员记住他们必须负责任地取消分配资源是不直观的。
-
如果在 Java 中没有适当的清理功能,那么您将陷入创建和跟踪 C++ 代码中分配的内存的困境。此外,如果您已经清楚地记录了如何使用这些功能,那是程序员的错,因为没有遵循文档。 Java 程序员必须意识到他们正在调用一种非垃圾收集语言,该语言正在动态创建对象,删除是在该语言的控制之下,而不是 Java。
标签: java c++ java-native-interface