一尘不染

记忆障碍和TLB

java

内存屏障可确保数据缓存保持一致。但是,是否可以保证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。


阅读 156

收藏
2020-12-03

共1个答案

一尘不染

映射是通过mmap64(FileChannel.map)完成的。当访问该地址时,将出现页面错误,内核将在其中为您读取/写入。在mmap期间不需要更新TLB。

在munmap期间,(所有cpus的)TLB是无效的,这是由MappedByteBuffer的终结处理的,因此munmap成本很高。

映射涉及很多同步,因此地址值不得损坏。

您是否有机会通过Unsafe尝试一些奇特的东西?

2020-12-03