System.arrayCopy 很慢

2023-11-27

我一直在尝试测量 System.arrayCopy 与 Arrays.copyOf 的性能,以便正确选择其中之一。只是为了基准测试,我还添加了手动复制,结果令我惊讶。 显然我错过了一些非常重要的东西,你能告诉我它是什么吗?实现如下(见前4种方法)。

public class ArrayCopy {

    public static int[] createArray( int size ) {
        int[] array = new int[size];
        Random r = new Random();
        for ( int i = 0; i < size; i++ ) {
            array[i] = r.nextInt();
        }
        return array;
    }

    public static int[] copyByArraysCopyOf( int[] array, int size ) {
        return Arrays.copyOf( array, array.length + size );
    }

    public static int[] copyByEnlarge( int[] array, int size ) {
        return enlarge( array, size );
    }

    public static int[] copyManually( int[] array, int size ) {
        int[] newArray = new int[array.length + size];
        for ( int i = 0; i < array.length; i++ ) {
            newArray[i] = array[i];
        }
        return newArray;
    }

    private static void copyArray( int[] source, int[] target ) {
        System.arraycopy( source, 0, target, 0, Math.min( source.length, target.length ) );
    }

    private static int[] enlarge( int[] orig, int size ) {
        int[] newArray = new int[orig.length + size];
        copyArray( orig, newArray );
        return newArray;
    }

    public static void main( String... args ) {
        int[] array = createArray( 1000000 );
        int runs = 1000;
        int size = 1000000;
        System.out.println( "****************** warm up #1 ******************" );
        warmup( ArrayCopy::copyByArraysCopyOf, array, size, runs );
        warmup( ArrayCopy::copyByEnlarge, array, size, runs );
        warmup( ArrayCopy::copyManually, array, size, runs );
        System.out.println( "****************** warm up #2 ******************" );
        warmup( ArrayCopy::copyByArraysCopyOf, array, size, runs );
        warmup( ArrayCopy::copyByEnlarge, array, size, runs );
        warmup( ArrayCopy::copyManually, array, size, runs );
        System.out.println( "********************* test *********************" );
        System.out.print( "copyByArrayCopyOf" );
        runTest( ArrayCopy::copyByArraysCopyOf, array, size, runs );
        System.out.print( "copyByEnlarge" );
        runTest( ArrayCopy::copyByEnlarge, array, size, runs );
        System.out.print( "copyManually" );
        runTest( ArrayCopy::copyManually, array, size, runs );
    }

    private static void warmup( BiConsumer<int[], Integer> consumer, int[] array, int size, int runs ) {
        for ( int i = 0; i < runs; i++ ) {
            consumer.accept( array, size );
        }
    }

    private static void runTest( BiConsumer<int[], Integer> consumer, int[] array, int size, int runs ) {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        long currentCpuTime = threadMXBean.getCurrentThreadCpuTime();
        long nanoTime = System.nanoTime();
        for ( int i = 0; i < runs; i++ ) {
            consumer.accept( array, size );
        }
        System.out.println( "-time = " + ( ( System.nanoTime() - nanoTime ) / 10E6 ) + " ms. CPU time = " + ( ( threadMXBean.getCurrentThreadCpuTime() - currentCpuTime ) / 10E6 ) + " ms" );
    }
}

结果显示,手动复制的性能提高了 30% 左右,如下所示:

****************** warm up #1 ******************
****************** warm up #2 ******************
********************* test *********************
copyByArrayCopyOf-time = 162.470107 ms. CPU time = 153.125 ms
copyByEnlarge-time = 168.6757949 ms. CPU time = 164.0625 ms
copyManually-time = 116.3975962 ms. CPU time = 110.9375 ms

我真的很困惑,因为我认为(可能现在仍然如此)System.arrayCopy由于它的诞生是复制数组的最佳方法,但我无法解释这个结果。


实际上,HotSpot 编译器足够智能,可以展开和矢量化手动复制循环 - 这就是结果代码似乎得到了很好优化的原因。

Why is System.arraycopy那么慢一点?它本来就是一个本地方法,你必须为本地调用付费,直到编译器将其优化为 JVM 内在方法。

但是,在您的测试中,编译器没有机会进行此类优化,因为enlarge方法被调用的次数不够多(即它不被认为是热的)。

我将向您展示一个强制优化的有趣技巧。改写enlarge方法如下:

private static int[] enlarge(int[] array, int size) {
    for (int i = 0; i < 10000; i++) { /* fool the JIT */ }

    int[] newArray = new int[array.length + size];
    System.arraycopy(array, 0, newArray, 0, array.length);
    return newArray;
}

空循环会触发后沿计数器溢出,进而触发编译enlarge方法。然后,空循环就会从编译的代码中消除,因此它是无害的。现在enlarge方法得到关于速度提高 1.5 倍比手动循环!

重要的是System.arraycopy紧随其后new int[]。在这种情况下,HotSpot 可以优化掉新分配数组的冗余归零。您知道,所有 Java 对象在创建后都必须立即清零。但只要编译器检测到数组在创建后立即被填充,它可能会消除归零,从而使结果代码更快。

P.S.@assylias 的基准很好,但它也受到以下事实的影响:System.arraycopy对于大型数组来说不是内在化的。如果数组较小arrayCopy每秒调用多次基准测试,JIT 认为它很热并且优化得很好。但对于大型数组,每次迭代的时间较长,因此每秒的迭代次数要少很多,并且 JIT 不处理arrayCopy as hot.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

System.arrayCopy 很慢 的相关文章

  • 如何选择主题与队列

    当我们设计应用程序时如何选择Topic Queue类型实现 我知道 a 如果有多个消费者使用该消息 则使用 Topicb 如果只有一个消费者则使用Queue 请提供更多需要考虑的点 比如并发 消息持久化 负载均衡等等 Thanks Rw 如
  • RSA Java 加密和 Node.js 解密不起作用

    我有一个系统 需要在 javascript 中生成 RSA 密钥对 然后将公钥存储在服务器端的数据库中 作为字符串 然后 Java 中的服务器端将使用存储的公钥对字符串进行加密密钥并将其发送到客户端 客户端将使用私钥解密该字符串 我在客户端
  • Spring批处理2.2 JavaConfig

    我正在尝试让 Spring Batch 2 2 与 JavaConfig 一起使用 如今他们有一个 EnableBatchProcessing设置很多东西的注释 默认情况下 该注释使用数据源作为其作业数据 但我们不想保存此数据 也不想为其创
  • HQL - 分页的行标识符

    有谁知道HQL是否有一个关键字来标识行 例如ROWID或ROWNUM 我想使用 HQL 实现分页 但我无法使用 setMaxResult 或 setFirstResult 因为我不直接使用会话对象 因此不使用 Query 对象 而只是将查询
  • 并行执行按位运算的代码

    我有这段代码 通过将该 AU 矩阵的每个字节 8 个元素打包到 A 中来减少内存消耗 从而使 100k 200k 矩阵占用更少的空间 正如您所期望的 这段代码需要永远运行 我也计划将行数增加到 200k 我正在一个非常强大的实例 CPU 和
  • 遍历后加快数组查找速度?

    我有一个123MB大的int数组 它基本上是这样使用的 private static int data new int 32487834 static int eval int c int p data c 0 p data p c 1 p
  • 如何将堆栈跟踪转换为字符串?

    转换结果的最简单方法是什么Throwable getStackTrace 到描述堆栈跟踪的字符串 Use Throwable printStackTrace PrintWriter pw https docs oracle com java
  • 获取 Spring Boot 中当前活动数据源的引用

    我想通过实现数据库数据初始化DataSourceInitializer 我将这些方法放在我的 Spring Boot 主方法下面 但似乎它根本没有被执行 我尝试故意删除字符只是为了触发一个错误来确认执行 什么也没有发生 Configurat
  • 在 Javascript 中实现 Zobrist 哈希

    我需要在 Javascript 中为国际象棋引擎实现 Zobrist 哈希 我想知道实现此目的的最佳方法是什么 现在 我不是计算机科学家 也从未上过正式的算法和数据结构课程 所以如果我在这方面有点偏离 我很抱歉 据我了解 我需要一个 64
  • Apache HTTPClient SSLPeerUnverifiedException

    使用 Apache HttpClient 4 2 1 使用从基于表单的登录示例复制的代码 http hc apache org httpcomponents client ga examples html http hc apache or
  • Java 多态性中的字段如何工作? [复制]

    这个问题在这里已经有答案了 我正在读书面试问题 http javabypatel blogspot in 2016 04 java interview questions html关于java 发现了很好的例子 但感到困惑 因为没有很好 更
  • NoSuchMethodError:org.springframework.data.repository.config.RepositoryConfigurationSource.getAttribute

    我正在尝试在 spring boot 应用程序中使用 spring data redis 来使用 redis 我正在创造JedisConnectionFactory如下 RedisStandaloneConfiguration config
  • JRuby调用了错误的方法

    我在调用 Java 方法时遇到了一个奇怪的问题JRuby http en wikipedia org wiki JRuby 在我的 Java 类中 这些方法定义了两次 看来 JRuby 调用了错误的方法 所以我尝试使用java method
  • 在 JavaScript/CoffeeScript 中确定一个数组是否包含另一个数组的内容

    在 JavaScript 中 如何测试一个数组是否包含另一个数组的元素 arr1 1 2 3 4 5 8 1 10 2 3 4 5 9 function name arr1 gt true 没有 set 函数可以执行此操作 但您可以简单地执
  • 使用 ProGuard 混淆代码后如何保持 javadoc 可见?

    我使用 progured 4 7 混淆了我的代码 并保留了 A 类 其中包含描述该类功能的 javadoc keep public class com mysite ClassA public keepattributes InnerCla
  • 从java类文件获取apache webcontents文件夹的绝对路径[重复]

    这个问题在这里已经有答案了 需要在动态 Web 应用程序内获取 java 类文件中的绝对路径 实际上我需要获取 apache webapps 文件夹的路径 部署 webapps 的位置 e g apache root webapps my
  • 在 R 中提取栅格的最快方法(提高我的可重现代码的时间)

    我想知道我是否已最大化提取栅格中某个点周围缓冲区域平均值的速度 本地的性能可以进一步提高吗 I use parallel mclapply已经 我知道我可以通过在集群上设置和运行它来获得进一步的收益 使用集群或获得更多的CPU不是我正在寻找
  • Scala 不可变 Map 速度慢

    当我创建地图时 我有一段代码 val map gtfLineArr 8 split map split collect case Array k v gt k v toMap 然后我使用这张地图来创建我的对象 case class MyOb
  • allure2 侦听器在控制台中输出步骤

    我正在使用 Allure2 和 TestNG 我想编写自己的侦听器 在控制台输出中打印 Steps 我在 allure 中看到了 StepLifecycleListener 接口 但我无法在 TestNg 中实现此侦听器 有什么指点吗 Ov
  • 从 Java 程序中获取局部变量的名称和类型

    这是我正在尝试的代码 JavaCompiler compilerA ToolProvider getSystemJavaCompiler int resultA compilerA run null null null Users a Do

随机推荐

  • Twisted:等待子任务完成

    在我的代码中 我有两个假设的任务 一个从生成器获取 url 并使用 Twisted 的 Cooperator 批量下载它们 另一个获取下载的源并异步解析它 我试图将所有获取和解析任务封装到一个 Deferred 对象中 该对象在下载所有页面
  • 从 Django 直接输入数据以生成 D3 图

    似乎所有 D3 示例图都采用外部 csv 或 tsv 文件作为输入数据 有没有办法修改代码以从 Django 中的变量获取数据 假设 data 是 JSON 格式 如何在图表中实现它 例如http bl ocks org 3885304 o
  • 某些应用程序如何阻止/替换平视通知?

    背景 自从 Android 上出现平视通知以来 有些人喜欢它的快速处理 但有些人讨厌它显示在应用程序 尤其是游戏 顶部 为了显示抬头通知 开发人员可以使用类似的东西 final NotificationCompat Builder buil
  • 为什么没有 std::move_if 算法?

    我在互联网上看到过一些地方 他们描述了使用std copy if with std make move iterator 但如果迭代器是前向迭代器 则会导致有效但未指定的 VBU 对象分散在源容器周围 拥有一个不是更好吗std move i
  • 如何在asp.net c# 中统计网站的访问者数量

    如何统计asp net c 网站的访问者数量 我正在使用下面的代码 在 global asax 页面中 void Application Start object sender EventArgs e Code that runs on a
  • Array.Find 和 IndexOf 用于查找完全相同对象的多个元素

    我无法获取完全相同对象的多个元素的当前元素的索引 b A D B D C E D F b contains D 替代版本 b A D B D C E D F Array FindAll b Predicate String args 0 c
  • BPMS 还是只是简单的编程?

    在实现业务流程时 您更喜欢什么 从开发人员的角度来看 业务流程管理系统 BPMS 还是您最喜欢的带有所需工具和框架 例如报告工具 的 IDE 从您的角度来看 与具有您个人工具和框架的 IDE 相比 BPMS 的最大好处是什么 好的 也许我应
  • Python Pandas,应用函数

    我正在尝试使用 apply 来避免iterrows 函数中的迭代器 然而 pandas 方法的记录很少 我找不到如何使用它的示例 除了蹩脚的 apply sq rt 在文档中 没有关于如何使用参数等的示例 不管怎样 这里有一个关于我尝试做的
  • 如何将 git-replace 推送到远程仓库?

    我使用 git Replace 来替换分支 没有共同祖先 22b2b25 来替换 master 中的提交 我希望这种改变是永久性的 我对以前的历史不感兴趣 在下面的输出中 前 5 个提交来自原始 master 分支 后 2 个来自不同的分支
  • appengine-maven-plugin 配置选项,例如 jvm 标志

    从1 7 4版本开始 Google App Engine 的官方 appengine maven plugin 是由 Google 发布的 它有一个任务 appengine devserver 来启动本地开发服务器 这个插件似乎没有任何 M
  • 带有 Kubernetes 客户端插件的 Jenkins - NoSuchMethodError

    将 jenkins 插件 Kubernetes Client 升级到版本 1 30 3 也适用于 1 31 1 后 当我开始构建时 我在 jenkins 日志中收到以下异常 Timer task org csanchez jenkins p
  • 删除流星身份验证的登录令牌

    我不确定以前是否有人问过这个问题 但是loginTokens变得非常大并且没有任何清理会使我的数据库大小增加 对此我们正在做什么 其他人正在做什么来管理这个问题 我指的是默认的Meteor users services其中有一个loginT
  • 使用Cgroups限制cpu使用

    我正在尝试使用 cgroups 来限制 CPU 使用率 我正在使用本指南https access redhat com documentation en US Red Hat Enterprise Linux 6 html Resource
  • 无法从使用本地类型参数化的另一个包中实现来自另一个包的泛型类型的特征

    此测试代码 playpen use std fmt Display Formatter Error struct MyLocalType type MyResult Result
  • 在java中绘制圆的切片?

    我想通过一个实心圆来表示一个计时器 该实心圆是在计时器的过程中逐段完全绘制的 IE 如果在 4 秒计时器内每 1 秒填充一次圆圈 第一个将显示四分之一圆 然后是半圆 然后是四分之三 最后是一个完整的圆 有没有办法在java中绘制这些圆的切片
  • 在 hbase shell 上执行 ValueFilter 或 ColumnFilter

    谁能告诉我如何从 hbase shell 命令行执行限定符过滤器或 ValueFilter 它与使用任何编程语言进行编码的方式非常相似 例如 import org apache hadoop hbase filter CompareFilt
  • Hadoop mapReduce 如何在 HDFS 中仅存储值

    我用它来删除重复的行 public class DLines public static class TokenCounterMapper extends Mapper
  • 字符串池行为

    我读了这个关于Java字符串池的问题并了解字符串池的基本概念 但仍然不了解其行为 第一 如果直接赋值并且 s1 和 s2 都引用池中的同一个对象 它就可以工作 String s1 a bc String s2 ab c System out
  • 阻止元素参与文本选择

    我有一些源代码 pre code 行号在单独的 div 选择文本后 行号会随之出现 并随后被复制 即使我选择源代码块上方和下方的元素 是否有任何方法可以防止行号成为选择的一部分 为了那些关闭 JavaScript 的人的利益 我想避免使用
  • System.arrayCopy 很慢

    我一直在尝试测量 System arrayCopy 与 Arrays copyOf 的性能 以便正确选择其中之一 只是为了基准测试 我还添加了手动复制 结果令我惊讶 显然我错过了一些非常重要的东西 你能告诉我它是什么吗 实现如下 见前4种方