使用JNA创建共享内存写入时触发java.lang.Error: Invalid memory access错误的求助
解决JNA创建共享内存时的Invalid memory access错误
我看到你在使用JNA创建Windows共享内存时触发了Invalid memory access错误,这个问题的核心原因是调用MapViewOfFile时传入了错误的权限参数。
问题根源
你代码里的这一行:
SharedMemoryData = myKernel32.MapViewOfFile(SharedMemoryHandle, PAGE_READWRITE, 0, 0, SharedMemorySize);
这里第二个参数用了PAGE_READWRITE,但这个常量是给CreateFileMapping用的内存页保护属性,而MapViewOfFile的第二个参数需要的是文件映射的访问权限常量,比如FILE_MAP_WRITE、FILE_MAP_READ或者FILE_MAP_ALL_ACCESS。传入错误的参数会导致映射的内存没有写入权限,所以执行setByte时会触发内存访问错误。
修复步骤
- 首先需要导入正确的权限常量,在你的import里添加:
import static com.sun.jna.platform.win32.WinNT.FILE_MAP_ALL_ACCESS;
- 修改
MapViewOfFile的调用,把第二个参数替换为FILE_MAP_ALL_ACCESS(或者根据需求用FILE_MAP_WRITE):
SharedMemoryData = myKernel32.MapViewOfFile(SharedMemoryHandle, FILE_MAP_ALL_ACCESS, 0, 0, SharedMemorySize);
另外,建议你添加错误排查逻辑,调用GetLastError来获取具体的系统错误码,方便定位问题,比如:
if (SharedMemoryHandle == null) { System.err.println("CreateFileMapping failed, error: " + myKernel32.GetLastError()); return; } if (SharedMemoryData == null) { System.err.println("MapViewOfFile failed, error: " + myKernel32.GetLastError()); return; }
完整的可运行示例
下面是包含资源释放逻辑的完整代码,避免内存泄漏:
import com.sun.jna.Pointer; import com.sun.jna.platform.win32.Kernel32; import static com.sun.jna.platform.win32.WinBase.INVALID_HANDLE_VALUE; import com.sun.jna.platform.win32.WinNT; import static com.sun.jna.platform.win32.WinNT.PAGE_READWRITE; import static com.sun.jna.platform.win32.WinNT.FILE_MAP_ALL_ACCESS; import com.sun.jna.win32.W32APIOptions; public class SharedMemoryTest { private final MyKernel32 myKernel32; private Pointer sharedMemoryData; private WinNT.HANDLE sharedMemoryHandle; public interface MyKernel32 extends Kernel32 { MyKernel32 INSTANCE = (MyKernel32) Native.load("kernel32", MyKernel32.class, W32APIOptions.DEFAULT_OPTIONS); } public SharedMemoryTest() { myKernel32 = MyKernel32.INSTANCE; } public void test() { String sharedMemoryName = "SomeSharedMemory"; int sharedMemorySize = 128; // 创建文件映射对象 sharedMemoryHandle = myKernel32.CreateFileMapping( (WinNT.HANDLE) INVALID_HANDLE_VALUE, null, PAGE_READWRITE, 0, sharedMemorySize, sharedMemoryName ); if (sharedMemoryHandle == null) { System.err.println("CreateFileMapping failed, error code: " + myKernel32.GetLastError()); return; } // 映射视图到进程地址空间 sharedMemoryData = myKernel32.MapViewOfFile( sharedMemoryHandle, FILE_MAP_ALL_ACCESS, 0, 0, sharedMemorySize ); if (sharedMemoryData == null) { System.err.println("MapViewOfFile failed, error code: " + myKernel32.GetLastError()); myKernel32.CloseHandle(sharedMemoryHandle); return; } // 读写共享内存 System.out.println("初始值: " + sharedMemoryData.getByte(0)); sharedMemoryData.setByte(0, (byte) 2); System.out.println("写入后的值: " + sharedMemoryData.getByte(0)); // 释放资源 myKernel32.UnmapViewOfFile(sharedMemoryData); myKernel32.CloseHandle(sharedMemoryHandle); } public static void main(String[] args) { new SharedMemoryTest().test(); } }
额外注意事项
- 记得在使用完共享内存后调用
UnmapViewOfFile和CloseHandle释放资源,避免内存泄漏。 - 如果是跨进程访问,确保其他进程使用相同的共享内存名称,并且映射时使用对应的访问权限。
内容的提问来源于stack exchange,提问作者soma wheels
相关产品推荐
相关产品推荐

