总览
如果直接使用Unsafe,则可能会导致JVM崩溃。 当您访问尚未映射的内存页面并且在Unix上的结果是SIGSEG(如果您访问页面0)或SIGBUS(如果您访问另一个未映射的页面)时,就会发生这种情况。
使用MethodHandles
用MethodHandle包装不安全的方法是可能的解决方案。 您可以将代码添加到“方法句柄”以检查零页面访问。 例如unsigned_ptr <4096。您应该将其添加到MethodHandle的原因是,它可以使优化检查变得更容易。
缺点是
- 您必须使用MethodHandles,它会使语法复杂化,并掩盖您的实际工作。
- 如果你不这样做是行不通的
- 它不涵盖总线错误,也不涵盖总线错误,因为整个应用程序的映射很复杂,并且可以随时在任何线程中更改。
- 优化边界检查需要优化器进行一些工作,这有待证明。
使用信号
如果已经有某种方法可以在硬件中做到这一点,那就可以了。 CPU已检查您尝试访问的页面是否有效,如果该页面不在缓存中,它将引发中断。 如果操作系统无法找到/创建此高速缓存未命中的映射,则此中断将变为信号。
如果JVM中已经只有一个信号处理程序,并且确实存在,那就是产生崩溃报告的原因。
如果只有某种方式,中断处理程序可以将错误或异常触发回触发它的代码。 就像Thread.currentThread()。stop(e); (你明白了)
优点
- 由于CPU已经完成了检查,因此不需要其他工作。
- 对优化器的最小更改(如果有)。
- 可能适用于从各种来源产生的信号。
- 使用信号是捕获Java之前的运行时错误的成熟/旧技术方法。
缺点
- 单一处理可能是一个停下来的操作(当前无法在Java中对其进行基准测试)
- 即使不是,触发错误时它的成本也可能更高。
- 您将不得不更改传统上未更改的信号处理程序。 即,有更多的经验来改变优化器。
可能引发的异常
可能会引发新的异常,但是我建议重用现有的异常。
访问页面0 – NullPointerException
访问页面0(不仅仅是访问NULL指针)将触发SIGSEG。 NPE是根据C对NULL指针的访问来命名的,与访问引用相比,使用NPE访问NULL指针可能更明显。 也就是说,由于Java没有指针,它可能被称为NullReferenceException。
无效的访问– IndexOutOfBoundsException
其他候选对象包括BufferUnderflowException(如果您的页面缺少映射区域),BufferOverflowException(如果您的页面没有映射区域)。
这些都是它们的共同点是它们是RuntimeException(s)。 如果引发了一个自定义的,更具描述性的异常,则RuntimeException可能与抛出的现有throwables一致。
结论
使性能最大化的常见技巧是: 不要用Java编写系统已经为您完成的事情。 在Chronicle中,我们使用OS对磁盘进行异步持久化,并且比再次用Java编写持久化磁盘更高效,更可靠。 同样,如果重新使用CPU和OS提供的功能,则捕获和处理无效的内存访问将更有效,更可靠。
一般来说,当每个操作系统做不同的事情以支持跨平台兼容性时,您都将重新编写操作系统功能,但是这样做仅需最低要求。 这就是为什么Java没有线程调度程序,并且相对而言,它几乎无法控制线程的运行方式。
虚拟内存处理非常古老且标准,以至于主要平台的工作方式基本相同。
翻译自: https://www.javacodegeeks.com/2014/06/making-unsafe-safer.html