内存屏障可确保数据缓存保持一致。但是,是否可以保证TLB保持一致?
我看到一个问题,即在线程之间传递MappedByteBuffer时,JVM(java 7更新1)有时会因内存错误(SIGBUS,SIGSEG)而崩溃。
例如
final AtomicReference<MappedByteBuffer> mbbQueue = new AtomicReference<>(); // in a background thread. MappedByteBuffer map = raf.map(MapMode.READ_WRITE, offset, allocationSize); Thread.yield(); while (!inQueue.compareAndSet(null, map)); // the main thread. (more than 10x faster than using map() in the same thread) MappedByteBuffer mbb = inQueue.getAndSet(null);
没有Thread.yield(),我有时会在force(),put()和C的memcpy()中崩溃,所有这些都表明我试图非法访问内存。使用Thread.yield(),我没有问题,但这听起来不像是可靠的解决方案。
有人遇到过这个问题吗?是否有关于TLB和内存屏障的保证?
编辑:操作系统是Centos 5.7,我已经在i7和Dual Xeon机器上看到了行为。
我为什么要这样做?由于写入消息的平均时间为35-100 ns(取决于长度),因此使用普通的write()并不那么快。如果我在当前线程中进行内存映射和清理,这将花费50-130微秒,而使用后台线程来执行,则主线程交换缓冲区大约需要3-5微秒。为什么我需要交换所有缓冲区?因为我正在写入许多GB的数据,所以ByteBuffer的大小不能超过2 GB。
映射是通过mmap64(FileChannel.map)完成的。当访问该地址时,将出现页面错误,内核将在其中为您读取/写入。在mmap期间不需要更新TLB。
在munmap期间,(所有cpus的)TLB是无效的,这是由MappedByteBuffer的终结处理的,因此munmap成本很高。
映射涉及很多同步,因此地址值不得损坏。
您是否有机会通过Unsafe尝试一些奇特的东西?