jit 会优化新对象吗

2023-12-26

我创建这个类是为了不可变并且具有流畅的 API:

public final class Message {
    public final String email;
    public final String escalationEmail;
    public final String assignee;
    public final String conversationId;
    public final String subject;
    public final String userId;

    public Message(String email, String escalationEmail, String assignee, String conversationId, String subject, String userId) {
        this.email = email;
        this.escalationEmail = escalationEmail;
        this.assignee = assignee;
        this.conversationId = conversationId;
        this.subject = subject;
        this.userId = userId;
    }

    public Message() {
        email = "";
        escalationEmail = "";
        assignee = "";
        conversationId = "";
        subject = "";
        userId = "";
    }

    public Message email(String e) { return new Message(e, escalationEmail, assignee, conversationId, subject, userId); }
    public Message escalationEmail(String e) { return new Message(email, e, assignee, conversationId, subject, userId); }
    public Message assignee(String a) { return new Message(email, escalationEmail, a, conversationId, subject, userId); }
    public Message conversationId(String c) { return new Message(email, escalationEmail, assignee, c, subject, userId); }
    public Message subject(String s) { return new Message(email, escalationEmail, assignee, conversationId, s, userId); }
    public Message userId(String u) { return new Message(email, escalationEmail, assignee, conversationId, subject, u); }

}

我的问题是,当像这样创建新对象时,优化器是否能够避免大量对象创建:

Message m = new Message()
    .email("f[email protected] /cdn-cgi/l/email-protection")
    .assignee("[email protected] /cdn-cgi/l/email-protection")
    .subject("subj");

制作一个单独的可变构建器对象有什么好处吗?

更新2:阅读 apangin 的答案后,我的基准测试无效。我将其保留在这里,以供参考如何不进行基准测试:)

Update:我冒昧地用这段代码自己测量了这一点:

public final class Message {
public final String email;
public final String escalationEmail;
public final String assignee;
public final String conversationId;
public final String subject;
public final String userId;

public static final class MessageBuilder {
    private String email;
    private String escalationEmail;
    private String assignee;
    private String conversationId;
    private String subject;
    private String userId;

    MessageBuilder email(String e) { email = e; return this; }
    MessageBuilder escalationEmail(String e) { escalationEmail = e; return this; }
    MessageBuilder assignee(String e) { assignee = e; return this; }
    MessageBuilder conversationId(String e) { conversationId = e; return this; }
    MessageBuilder subject(String e) { subject = e; return this; }
    MessageBuilder userId(String e) { userId = e; return this; }

    public Message create() {
        return new Message(email, escalationEmail, assignee, conversationId, subject, userId);
    }

}

public static MessageBuilder createNew() {
    return new MessageBuilder();
}

public Message(String email, String escalationEmail, String assignee, String conversationId, String subject, String userId) {
    this.email = email;
    this.escalationEmail = escalationEmail;
    this.assignee = assignee;
    this.conversationId = conversationId;
    this.subject = subject;
    this.userId = userId;
}

public Message() {
    email = "";
    escalationEmail = "";
    assignee = "";
    conversationId = "";
    subject = "";
    userId = "";
}

public Message email(String e) { return new Message(e, escalationEmail, assignee, conversationId, subject, userId); }
public Message escalationEmail(String e) { return new Message(email, e, assignee, conversationId, subject, userId); }
public Message assignee(String a) { return new Message(email, escalationEmail, a, conversationId, subject, userId); }
public Message conversationId(String c) { return new Message(email, escalationEmail, assignee, c, subject, userId); }
public Message subject(String s) { return new Message(email, escalationEmail, assignee, conversationId, s, userId); }
public Message userId(String u) { return new Message(email, escalationEmail, assignee, conversationId, subject, u); }


static String getString() {
    return new String("hello");
    // return "hello";
}

public static void main(String[] args) {
    int n = 1000000000;

    long before1 = System.nanoTime();

    for (int i = 0; i < n; ++i) {
        Message m = new Message()
                .email(getString())
                .assignee(getString())
                .conversationId(getString())
                .escalationEmail(getString())
                .subject(getString())
                .userId(getString());
    }

    long after1 = System.nanoTime();

    long before2 = System.nanoTime();

    for (int i = 0; i < n; ++i) {
        Message m = Message.createNew()
                .email(getString())
                .assignee(getString())
                .conversationId(getString())
                .escalationEmail(getString())
                .subject(getString())
                .userId(getString())
                .create();
    }

    long after2 = System.nanoTime();



    System.out.println("no builder  : " + (after1 - before1)/1000000000.0);
    System.out.println("with builder: " + (after2 - before2)/1000000000.0);
}


}

我发现如果字符串参数不是新对象,但都是相同的(请参阅 getString 中的注释代码),差异是显着的(构建器更快)

在我想象的更现实的场景中,当所有字符串都是新对象时,差异可以忽略不计,并且 JVM 启动会导致第一个字符串稍微慢一点(我尝试了两种方法)。

使用“新字符串”,代码总共也慢了很多倍(我不得不减少n),也许表明正在对“新消息”进行一些优化,但对“新字符串”没有进行优化。


是的,HotSpot JIT 可以消除本地上下文中的冗余分配。

这种优化是由逃逸分析 http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis从 JDK 6u23 开始启用。它经常与栈上分配相混淆,但实际上它更强大,因为它不仅允许在栈上分配对象,还可以通过用变量替换对象字段(标量替换)来完全消除分配,这些变量会受到进一步的影响。优化。

优化控制由-XX:+EliminateAllocationsJVM 选项默认为 ON。


由于分配消除优化,您创建的两个示例Message对象以同样的方式有效地工作。它们不分配中间对象;只是最后一张。

您的基准测试显示了误导性的结果,因为它收集了许多常见的陷阱 http://www.oracle.com/technetwork/articles/java/architect-benchmarking-2266277.html微基准测试:

  • 它在一个方法中整合了多个基准;
  • 它测量一个OSR stub https://stackoverflow.com/questions/9105505/differences-between-just-in-time-compilation-and-on-stack-replacement而不是最终编译版本;
  • 它不进行预热迭代;
  • 它不消耗结果等。

让我们正确测量它JMH http://openjdk.java.net/projects/code-tools/jmh/。作为奖励,JMH 拥有分配分析器(-prof gc)显示每次迭代实际分配了多少字节。我添加了运行的第三个测试EliminateAllocations禁用优化以显示差异。

package bench;

import org.openjdk.jmh.annotations.*;

@State(Scope.Benchmark)
public class MessageBench {

    @Benchmark
    public Message builder() {
        return Message.createNew()
                .email(getString())
                .assignee(getString())
                .conversationId(getString())
                .escalationEmail(getString())
                .subject(getString())
                .userId(getString())
                .create();
    }

    @Benchmark
    public Message immutable() {
        return new Message()
                .email(getString())
                .assignee(getString())
                .conversationId(getString())
                .escalationEmail(getString())
                .subject(getString())
                .userId(getString());
    }

    @Benchmark
    @Fork(jvmArgs = "-XX:-EliminateAllocations")
    public Message immutableNoOpt() {
        return new Message()
                .email(getString())
                .assignee(getString())
                .conversationId(getString())
                .escalationEmail(getString())
                .subject(getString())
                .userId(getString());
    }

    private String getString() {
        return "hello";
    }
}

这是结果。两个都builder and immutable性能相同,每次迭代仅分配 40 个字节(正好是一个迭代的大小)Message目的)。

Benchmark                                        Mode  Cnt     Score     Error   Units
MessageBench.builder                             avgt   10     6,232 ±   0,111   ns/op
MessageBench.immutable                           avgt   10     6,213 ±   0,087   ns/op
MessageBench.immutableNoOpt                      avgt   10    41,660 ±   2,466   ns/op

MessageBench.builder:·gc.alloc.rate.norm         avgt   10    40,000 ±   0,001    B/op
MessageBench.immutable:·gc.alloc.rate.norm       avgt   10    40,000 ±   0,001    B/op
MessageBench.immutableNoOpt:·gc.alloc.rate.norm  avgt   10   280,000 ±   0,001    B/op
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

jit 会优化新对象吗 的相关文章

随机推荐

  • 作为 Snakemake 工作流程输入的值数组

    我开始将我的工作流程从Nextflow to Snakemake并且已经在我的管道开始处碰壁了 管道通常以数字列表开头 代表我们检测器的 运行编号 我所拥有的例如是run list txt like detector id run numb
  • 如何使用 EF Core 在 ASP.NET Core 中取消应用迁移

    当我跑步时PM gt Remove Migration context BloggingContext在 VS2015 中使用 EF Core 的 ASP NET Core 项目出现以下错误 System InvalidOperationE
  • fastApi 中的 python 全局变量无法正常工作

    我有一个简单的 fastApi 演示应用程序 它实现了一个功能 通过调用名为changeResponse的post api来获取不同的响应json changeResponse api只是改变了一个全局变量 另一个api通过同一个全局变量返
  • 手机上的陀螺仪漂移

    很多帖子都讨论了陀螺仪漂移问题 有些人说陀螺仪读数有漂移 但其他人说积分有漂移 原始陀螺仪读数有漂移 link https stackoverflow com questions 1586658 combine gyroscope and
  • 在 ASCIIFoldingFilter 中使用静态“foldToAscii”方法

    我一直在使用 ASCII 折叠过滤器来处理变音符号 不仅适用于弹性搜索中的文档 还适用于各种其他类型的字符串 public static String normalizeText String text boolean shouldTrim
  • 单个解析服务器中的多个应用程序

    我花了整整一周的时间将 parse com 上托管的应用程序迁移到解析服务器 设法使一切完美运行 唯一的问题是让它在单个硬件上运行多个应用程序 而无需为此分配服务器应用程序它有 它会变得昂贵 我读了这个讨论 https github com
  • android 多数据源的分页库DataSource.Factory

    我有多个数据源 但只有一个DataSourceFactory 因此 所有来源都共享一个工厂 我需要每个数据源一个 DataSourceFactory 在我的应用程序中 我有多个 RecyclerViews 视图 因此有多个自定义数据源 那么
  • PHP 5.4 中删除 safe_mode 后的安全性在哪里

    我心里有一个棘手的问题 safe modePHP 5 4 中已删除 那么此删除的安全性如何 这是否意味着任何应用程序都可以执行任何程序 为此目的使用什么技术来防止此类暴力行为 本文 http ilia ws archives 18 PHPs
  • java.lang.SecurityException AWSCredentialsProvider 签名者信息不匹配

    我正在使用 2 个亚马逊提供的库 redshift jdbc42 1 2 27 1051 and aws java sdk core 1 11 600 两个库都定义了一个类AWSCredentialsProvider包装下com amazo
  • 将文件从服务器下载到 Ionic2 应用程序中

    我需要在我的中实现一个功能Ionic2用户可以将特定视频文件下载到 Ionic2 应用程序中 经检查Ionic Native部分 我发现以下插件可用 File 文件选择器 文件开启器 文件路径 但找不到诸如 cordova 插件 文件传输
  • 如何在Windows 10上更改Node JS进程名称?

    我有一个node js在 Windows 10 上运行的进程 我想更改进程的名称 以便可以获得一些性能详细信息 我尝试改变流程 标题的财产process对象但是 它不会反映在电源外壳中 我只能找到node作为进程名称 有没有其他方法可以更改
  • Exhaustive-deps 规则无法将自定义挂钩的结果识别为 React 参考

    想象一个钩子 export function useMounted const mounted React useRef
  • Spring Boot 多数据库:没有 EntityManagerFactoryBuilder 类型的合格 bean

    我们的 Spring Boot 应用程序中有两个数据库 称为源数据库和目标数据库 这是这些的配置 源配置 package com alex myapp config import javax persistence EntityManage
  • PHP 字符串类型提示 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何在另一个线程完成时停止一个线程

    我有这个代码 Thread thread1 new Thread this DoSomething1 Thread thread2 new Thread this DoSomething2 thread1 Start thread2 Sta
  • OpenSSL:加密/解密例程的输入和输出缓冲区可以相同吗?

    例如 在 int EVP EncryptUpdate EVP CIPHER CTX ctx unsigned char out int outl unsigned char in int inl can out in 我只是偶然发现这个问题
  • 如何限制临时表的大小?

    我的数据库中有较大的 InnoDB 表 显然 用户能够使用 JOIN 进行 SELECT 从而生成临时的大型 因此位于磁盘上 表 有时 它们太大以至于耗尽了磁盘空间 导致各种奇怪的问题 有没有办法限制临时表的最大大小对于磁盘上的表 这样表就
  • 将参数值作为rails中的查询字符串传递给redirect_to

    这应该很简单 但我似乎找不到简单的答案 如何将当前请求中的参数值传递到redirect to 调用中 我想将一些表单值传递到 GET 重定向的查询字符串中 我想做这样的事情 redirect to thing foo gt params f
  • 查找多个 NumPy 数组的中值

    我有一个创建大约 50 个数组的 for 循环 数组的长度为 240 我试图找出计算数组每个元素的中值的最佳方法 本质上 我想获取循环中创建的每个数组的第一个元素 将它们放入列表中 然后找到中位数 然后对其他 239 个元素执行相同的操作
  • jit 会优化新对象吗

    我创建这个类是为了不可变并且具有流畅的 API public final class Message public final String email public final String escalationEmail public