在写另一个问题的答案时,我注意到JIT优化的一个奇怪的边界情况.
以下程序不是 "Microbenchmark",也不是为了可靠地测量执行时间(如另一个问题的答案中所指出的).它仅用作MCVE来重现该问题:
class MissedLoopOptimization
{
public static void main(String args[])
{
for (int j=0; j<3; j++)
{
for (int i=0; i<5; i++)
{
long before = System.nanoTime();
runWithMaxValue();
long after = System.nanoTime();
System.out.println("With MAX_VALUE : "+(after-before)/1e6);
}
for (int i=0; i<5; i++)
{
long before = System.nanoTime();
runWithMaxValueMinusOne();
long after = System.nanoTime();
System.out.println("With MAX_VALUE-1 : "+(after-before)/1e6);
}
}
}
private static void runWithMaxValue()
{
final int n = Integer.MAX_VALUE;
int i = …
Run Code Online (Sandbox Code Playgroud) 如果有人能够提供关于两个JVM的优缺点的简要信息,因为它们都依赖于标准JVM规范.
我试图找出是否有办法从正在运行的java进程中确定JVM启动属性.具体来说,我试图找出存储-Xmx(最大堆大小)和-XX:MaxPermSize等参数的位置.我正在运行Sun的1.6 jvm.
如果您想知道我为什么要这样做,我有许多JVM网络服务器可能正确配置也可能没有配置,我想将其添加到启动代码检查中.检查一下到处部署的java代码比手动查找和检查所有jvm启动文件要容易得多.现在,jvm配置文件的好坏不是我们构建过程的一部分,也不是检查到源代码控制.
我正在优化LZF压缩算法的纯java实现,它涉及大量的byte []访问和基本的int数学,用于散列和比较.性能确实很重要,因为压缩的目标是降低I/O要求.我没有发布代码,因为它尚未清理,并且可能会进行大量重组.
在我因为过早优化而受到攻击之前:基本算法已经非常出色,但Java实现的速度不到等效C的2/3.我已经用System.arraycopy替换了复制循环,致力于优化循环并消除了un - 需要的操作.
我大量使用bit twiddling并将字节打包为整数,以实现性能,以及移位和屏蔽.
出于法律原因,我无法查看类似库中的实现,并且现有库具有过于严格的许可条款.
另外:如果有人有详细说明Hotspot优化和分支性能的内容的链接,那么欢迎这些.我对字节码有足够的了解,网站分析字节码而不是源代码级别的性能会有所帮助.
这是从提供的HotSpot内部维基链接获取的:https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
HotSpot将消除所有for循环中的边界检查,具有以下条件:
例: int val = array[index*2 + 5]
要么: int val = array[index+9]
不: int val = array[Math.min(var,index)+7]
这是一个示例版本.不要窃取它,因为它是H2数据库项目的未发布版本的代码.最终版本将是开源的.这是对代码的优化:H2 CompressLZF代码
从逻辑上讲,这与开发版本相同,但是它使用for(...)循环来逐步执行输入,并使用if/else循环来实现文字和反向引用模式之间的不同逻辑.它减少了阵列访问和模式之间的检查.
public int compressNewer(final byte[] in, final int inLen, final byte[] out, int …
Run Code Online (Sandbox Code Playgroud) java optimization performance jvm-hotspot bounds-check-elimination
运行Java 1.6(1.6.0_03-b05)应用程序时,我添加了-XX:+PrintCompilation
标志.在某些方法的输出中,特别是我知道的一些方法被大量调用,我看到了文本made not entrant
和made zombie
.
这些是什么意思?最好的猜测是,在重新编译该方法或具有更高优化的依赖项之前,它是一个反编译步骤.真的吗?为什么"僵尸"和"参赛者"?
例如,其中一些行之间有相当长的时间:
[... near the beginning]
42 jsr166y.LinkedTransferQueue::xfer (294 bytes)
[... much later]
42 made not entrant jsr166y.LinkedTransferQueue::xfer (294 bytes)
--- n sun.misc.Unsafe::compareAndSwapObject
170 jsr166y.LinkedTransferQueue::xfer (294 bytes)
170 made not entrant jsr166y.LinkedTransferQueue::xfer (294 bytes)
4% jsr166y.LinkedTransferQueue::xfer @ 29 (294 bytes)
171 jsr166y.LinkedTransferQueue::xfer (294 bytes)
[... even later]
42 made zombie jsr166y.LinkedTransferQueue::xfer (294 bytes)
170 made zombie jsr166y.LinkedTransferQueue::xfer (294 bytes)
171 made not entrant jsr166y.LinkedTransferQueue::xfer (294 bytes)
172 jsr166y.LinkedTransferQueue::xfer (294 …
Run Code Online (Sandbox Code Playgroud) 我正在查看运行Alfresco的JVM配置选项,主要是Alfresco Wiki上的这个文档.其中一个建议是使用JVM标志和.这样做的理由是:-Xcomp
-Xbatch
如果您希望Hotspot预编译类,可以添加[-Xcomp和-Xbatch].但是,这将显着增加服务器启动时间,但会突出显示以后可能遇到的缺失依赖项.
从我在其他地方读到的关于-Xcomp
和-Xbatch
旗帜的内容,我想知道它们是否确实提供了任何好处.
-Xcomp
获得HotSpot以预先编译所有代码并进行最大程度的优化,从而推导出VM将通过系统的标准运行获得的任何分析.-Xbatch
停止后台编译,这意味着在编译完成之前导致代码被编译的线程.但是,在编译完成后,先前阻塞的线程将不会运行已编译的代码,它仍将运行解释的代码.这是Java 6(Mustang)的一个变化 - 在Mustang之前,由于-Xbatch
标志的存在而被阻止编译的线程一旦编译完成就保证在编译的代码中运行.因此,我猜测-Xbatch
标志的推荐是在较旧的VM上运行Alfresco的遗留物.有人有想法吗?我倾向于摆脱这两面旗帜并依靠虚拟机来解决问题.
我想添加两件事,首先是我还没有访问Alfresco实例来测试这个,其次我不知道什么样的机器托管Alfresco而不是通过查看其他配置选项它必须是64位VM.尽管如此,我希望社区将有一些有用的输入,可能来自一般的HotSpot调整观点.
我得到了下面的汇编列表作为我的java程序的JIT编译的结果.
mov 0x14(%rsp),%r10d
inc %r10d
mov 0x1c(%rsp),%r8d
inc %r8d
test %eax,(%r11) ; <--- this instruction
mov (%rsp),%r9
mov 0x40(%rsp),%r14d
mov 0x18(%rsp),%r11d
mov %ebp,%r13d
mov 0x8(%rsp),%rbx
mov 0x20(%rsp),%rbp
mov 0x10(%rsp),%ecx
mov 0x28(%rsp),%rax
movzbl 0x18(%r9),%edi
movslq %r8d,%rsi
cmp 0x30(%rsp),%rsi
jge 0x00007fd3d27c4f17
Run Code Online (Sandbox Code Playgroud)
我对这test
条指令的理解在这里没用,因为测试的主要思想是
标志SF,ZF,PF被修改,而AND的结果被丢弃.
这里我们不使用这些结果标志.
这是JIT中的错误还是我错过了什么?如果是,报告的最佳位置在哪里?谢谢!
关于AES-NI,Oracle有关Java 8的说法:
添加了硬件内在函数以使用高级加密标准(AES).UseAES和UseAESIntrinsics标志可用于为Intel硬件启用基于硬件的AES内在函数.硬件必须是2010或更新的Westmere硬件.例如,要启用硬件AES,请使用以下标志:
Run Code Online (Sandbox Code Playgroud)-XX:+UseAES -XX:+UseAESIntrinsics
要禁用硬件AES,请使用以下标志:
Run Code Online (Sandbox Code Playgroud)-XX:-UseAES -XX:-UseAESIntrinsics
但它并不表示默认情况下是否启用AES内在函数(对于支持它的处理器).所以问题很简单:如果处理器支持AES-NI,是否使用了AES内在函数?
奖金问题:有没有办法测试是否使用AES-NI?我想你可以根据性能来猜测,但这不是一种最佳或确定的测试方法.
对于不熟悉AES-NI内在函数的读者:它使用AES-NI指令集用预编译的机器代码替换字节代码.这是由JVM发生的,因此它不会出现在Java运行时或字节码的API中.
我已经使用过-XX:+PrintCompilation
,我知道JIT编译器的基本技术以及使用JIT编译的原因.
然而,我仍然没有发现JVM如何决定JIT编译方法,即"正确的时间来到JIT编译方法".
我是否正确地假设每个方法都开始被解释,并且只要它不被归类为"热方法"它就不会被编译?我有一些东西在脑后,我读到一个方法被认为是"热",当它执行至少10.000次(解释方法10.000次后,它将被编译),但我不得不承认我是不确定这个或我在哪里读到这个.
总结一下我的问题:
(1)只要没有将每种方法归类为"热"方法(并因此已被编译),或者即使它们不是"热门",也有理由编制方法?
(2)JVM如何将方法分为"非热"和"热"方法?执行次数?还要别的吗?
(3)如果"热"方法存在某些阈值(如执行次数),是否有Java标志(-XX:...
)来设置此阈值?
XX的默认值是什么:MaxDirectMemorySize?
java ×10
jvm-hotspot ×10
jvm ×6
jit ×4
aes ×1
assembly ×1
cpu ×1
cryptography ×1
jrockit ×1
optimization ×1
performance ×1