HmacSHA1的Java Mac.getInstance很慢

Axl*_*xle 7 java random macos cryptography hmac

我在运行OSX 10.9.4,1.7GHz i7,8GB内存的Macbook Air上运行以下Java程序.我安装了Java Cryptography Extension(JCE).

import javax.crypto.Mac;

public class Main {
  public static void main(String[] args) throws Exception {
    Mac.getInstance("HmacSHA1");
  }
}
Run Code Online (Sandbox Code Playgroud)

运行这个简单的程序会导致运行时间超过5秒!

$ javac -version
javac 1.7.0_45
$ javac Main.java
$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
$ time java Main

real    0m5.326s
user    0m0.390s
sys     0m0.033s
Run Code Online (Sandbox Code Playgroud)

我做了很多搜索,但没有找到解决方法或解释的方法.

以前有人听说过这个问题吗?或者知道一种方法让我调试正在发生的事情?当你的单位测试一直持续到目前为止,对你的单位测试给予5秒的惩罚是非常令人沮丧的.

编辑: 这是程序内部的时间安排和安全提供程序列表:

import java.security.Provider;
import java.security.Security;
import javax.crypto.Mac;

public class Main {
  public static void main(String[] args) throws Exception {
    for (Provider p: Security.getProviders()) {
        System.out.println(p.getName() + " " + p.getVersion() + " " + p.getInfo());
    }
    long start = System.currentTimeMillis();
    Mac.getInstance("HmacSHA1");
    System.out.println(System.currentTimeMillis() - start + "ms");
  }
}

$ java Main
SUN 1.7 SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; JavaLoginConfig Configuration)
SunRsaSign 1.7 Sun RSA signature provider
SunEC 1.7 Sun Elliptic Curve provider (EC, ECDSA, ECDH)
SunJSSE 1.7 Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)
SunJCE 1.7 SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC)
SunJGSS 1.7 Sun (Kerberos v5, SPNEGO)
SunSASL 1.7 Sun SASL provider(implements client mechanisms for: DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5, NTLM; server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5, NTLM)
XMLDSig 1.0 XMLDSig (DOM XMLSignatureFactory; DOM KeyInfoFactory)
SunPCSC 1.7 Sun PC/SC provider
Apple 1.1 Apple Provider
5224ms
Run Code Online (Sandbox Code Playgroud)

编辑2:

弄清楚如何在代码上运行HPROF.

$ java -agentlib:hprof=cpu=times Main
$ cat java.hprof.txt
...
TRACE 308670:
java.net.InetAddress$1.lookupAllHostAddr(InetAddress.java:Unknown line)
java.net.InetAddress.getAddressesFromNameService(InetAddress.java:Unknown line)
java.net.InetAddress.getLocalHost(InetAddress.java:Unknown line)
javax.crypto.JarVerifier.getSystemEntropy(JarVerifier.java:Unknown line)
...
CPU TIME (ms) BEGIN (total = 6680) Sat Aug 16 05:59:39 2014
rank   self  accum   count trace method
   1 74.87% 74.87%       1 308670 java.net.InetAddress$1.lookupAllHostAddr
...
Run Code Online (Sandbox Code Playgroud)

因此,似乎由于某种原因,JarVerifier试图从系统中获取熵,这导致程序在InetAddress $ 1.lookupAllHostAddr中花费5秒...

编辑3:

将Java更新为"1.7.0_67"并不能解决问题.

Axl*_*xle 7

我找到了解决方案.在编辑2中可以看到,Mac.getInstance()似乎调用javax.crypto.JarVerifier.getSystemEntropy(),最终调用java.net.InetAddress.getLocalHost().根据这篇文章,Java 7改变了InetAddress寻找本地主机的方式.由于某种原因,这导致我的机器lookupAllHostAddr,这需要约5秒钟完成.

本文的一条评论列出了适合我的解决方案,即添加我的主机名/etc/hosts.下列:

127.0.0.1       localhost
255.255.255.255 broadcasthost
::1             localhost
fe80::1%lo0     localhost
Run Code Online (Sandbox Code Playgroud)

改变为

127.0.0.1       localhost     <replace-me>.local
255.255.255.255 broadcasthost
::1             localhost
fe80::1%lo0     localhost
Run Code Online (Sandbox Code Playgroud)

更改为hosts文件后,我的时间又恢复到合理的200毫秒.

$ time java Main

real    0m0.242s
user    0m0.379s
sys 0m0.034s
Run Code Online (Sandbox Code Playgroud)

  • +1,你做了一个很好的工作跟踪这个.我也在查看字节码,并且getSystemEntropy()执行其他可以减慢速度的事情,比如你的临时目录中有一百万个文件(属性"java.io.tmpdir"). (2认同)