Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 9:AES-GCM性能_Java_Performance_Encryption_Java 11_Aes Gcm - Fatal编程技术网

Java 9:AES-GCM性能

Java 9:AES-GCM性能,java,performance,encryption,java-11,aes-gcm,Java,Performance,Encryption,Java 11,Aes Gcm,我运行了一个简单的测试,通过在循环中加密字节缓冲区来测量Java9中的性能。结果有些混乱。本机(硬件)加速似乎可行,但并不总是如此。更具体地说 在循环中加密1MB缓冲区时,前50秒的速度约为60 MB/秒。然后它跳到1100 MB/秒,并保持不变。JVM是否决定在50秒(或3GB数据)后激活硬件加速?可以配置吗? 我在哪里可以阅读有关新的AES-GCM实施()的信息 加密100MB缓冲区时,硬件加速根本不起作用。速度为60 MB/秒 我的测试代码如下所示: int plen = 1024*102

我运行了一个简单的测试,通过在循环中加密字节缓冲区来测量Java9中的性能。结果有些混乱。本机(硬件)加速似乎可行,但并不总是如此。更具体地说

  • 在循环中加密1MB缓冲区时,前50秒的速度约为60 MB/秒。然后它跳到1100 MB/秒,并保持不变。JVM是否决定在50秒(或3GB数据)后激活硬件加速?可以配置吗? 我在哪里可以阅读有关新的AES-GCM实施()的信息
  • 加密100MB缓冲区时,硬件加速根本不起作用。速度为60 MB/秒 我的测试代码如下所示:

    int plen = 1024*1024;
    byte[] input = new byte[plen];
    for (int i=0; i < input.length; i++) { input[i] = (byte)i;}
    byte[] nonce = new byte[12];
    ...
    // Uses SunJCE provider
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    byte[] key_code = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    SecretKey key = new SecretKeySpec(key_code, "AES");
    SecureRandom random = new SecureRandom();
    
    long total = 0;
    while (true) {
      random.nextBytes(nonce);
      GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce);
      cipher.init(Cipher.ENCRYPT_MODE, key, spec);
      byte[] cipherText = cipher.doFinal(input);
      total += plen;
      // print delta_total/delta_time, once in a while
    }
    
    intplen=1024*1024;
    字节[]输入=新字节[plen];
    对于(inti=0;i
    2019年2月更新:HotSpot已被修改以解决此问题。该修复程序在Java13中应用,并向后移植到Java11和Java12

    ,


    2019年7月16日更新:新发布的Java版本(Java 11.0.4)修复了此问题。

    感谢@Holger指出了正确的方向。使用多个
    cipher.update
    调用预结束
    cipher.doFinal
    ,将几乎立即触发硬件加速

    基于此参考,我在每次更新中使用4KB块。现在1MB100MB缓冲区都以1100 MB/sec的速度加密(几十毫秒后)

    解决办法是替换

    byte[] cipherText = cipher.doFinal(input);
    


    关于这个问题的一些更新

  • 3月下旬发布的Java10也有同样的问题,可以通过相同的解决方法绕过这个问题-仅用于数据加密

  • 该解决方案基本上不适用于数据解密——在Java 9和Java 10中都是如此


  • 我已经向Java平台提交了一份bug报告。这个问题在Java13中得到了修复。该修复程序还向后移植到Java11和Java12

    ,,

    2019年7月16日发布的Java版本(Java 11.0.4)解决了这个问题。

    我认为您应该阅读并应用其中介绍的技术。你可能会对你所测量的东西有更好的了解。例如,您应该在基准测试中包括一个预热阶段。您看到的情况可能是因为JIT编译器在50秒后启动并优化代码。看来调用的数量对优化触发器很重要,当然,考虑到相同的时间,处理大量小缓冲区意味着比处理几个大缓冲区更多的调用。注意处理一个大的缓冲区的可能性,反复调用
    update
    来处理一小部分缓冲区,最后调用
    doFinal
    来处理最后一块缓冲区…@Lii你是对的,热身很可能会有帮助,但这不是微基准,这需要相当长的时间,而且应该会更好。@Eugene这不是关于选择不同的分支。我尝试了不同的缓冲区大小和不同的缓冲区大小。您可以在一秒钟内预热代码,方法是使用一个很小的缓冲区频繁地执行代码以获得优化,然后使用一个巨大的缓冲区调用相同的代码,仍然可以从已经应用的优化中获益。这表明重要的只是调用的数量。当您通过重复执行
    update
    操作,然后执行
    doFinal
    ,重构代码以始终处理缓冲区的一小部分时,缓冲区的总大小变得无关紧要…@gg123这应该作为错误报告。巨大区块的加密应该自动拆分,对于解密,应该找到一些解决方案。Apache PArquet团队开始讨论OpenJDK列表:
    int clen = plen + GCM_TAG_LENGTH;
    byte[] cipherText = new byte[clen];
    
    int chunkLen = 4 * 1024;
    int left = plen;
    int inputOffset = 0;
    int outputOffset = 0;
    
    while (left > chunkLen) {
      int written = cipher.update(input, inputOffset, chunkLen, cipherText, outputOffset);
      inputOffset += chunkLen;
      outputOffset += written;
      left -= chunkLen;
    }
    
    cipher.doFinal(input, inputOffset, left, cipherText, outputOffset);