【问题标题】:Java Lambda performance vs declared Suppliers/FunctionsJava Lambda 性能与声明的供应商/功能
【发布时间】:2019-04-09 23:12:18
【问题描述】:

我开始学习如何在 java8 中使用Optional 进行开发。可能是有人记录在案,但我一直在使用谷歌,但没有准确的结果。

orElseGet 方法有不同的可能实现,我不确定 java 在某些情况下是否可以更好地处理内存,或者是否几乎相同。

假设我在一个定义了Optional 的类中有一个方法:

class myClass {

  final static private Supplier<Object> MY_SUPPLIER = () -> new Object();

  private void myMethod1 () {
    Optional<Object> x; // somehow Initialized
    Object y = x.orElseGet(() -> new Object());
  }

  private void myMethod2 () {
    Optional<Object> x; // somehow Initialized
    Object y = x.orElseGet(MY_SUPPLIER);
  }
}

从我谦虚的角度来看,这一秒在 java 中应该有更好的内存管理,因为它只声明了一次 Supplier,并且总是使用相同的。

1) 这是真的吗?

现在,让我们更进一步,假设我们需要根据参数提供不同的对象。

class myClass2 {

  final static private Function<String, Supplier<AnyCustomClass>> MY_SUPPLIER_PROVIDER = (p) -> () -> new AnyCustomClass(p);

  private void myMethod1 (String arg) {
    Optional<AnyCustomClass> x; // somehow Initialized
    AnyCustomClass y = x.orElseGet(() -> new AnyCustomClass(arg));
  }

  private void myMethod2 (String arg) {
    Optional<AnyCustomClass> x; // somehow Initialized
    AnyCustomClass y = x.orElseGet(MY_SUPPLIER_PROVIDER.apply(arg));
  }
}

在这种情况下,根据参数,每次返回不同的供应商。

2) java 在这里也有更好的内存管理吗?

3) 他们是否以某种方式“缓存”了 arg 取相同的值?

编辑

通过观看Does a lambda expression create an object on the heap every time it's executed? ,我了解我的一流行为得到了解答。由于没有局部变量,所以会创建一个单例(至少是oracle jvm)

然而,我觉得这个答案不能提供准确的信息来回答我的 2) 和 3)

【问题讨论】:

标签: java performance memory-management


【解决方案1】:

这两种方法的区别在于您重用了供应商,这将重用对象,从而为您节省一些内存。您需要注意的是可能的线程问题。由于您使用的是相同的内存,因此您需要确保不同的线程不会尝试使用相同的对象。

所以回答你的问题:

1.) 是的,但您可能还有其他问题。

2.) 和第一个问题一样吗?您正在重用函数的一个实例。这不是你应该在这种情况下使用 Function 的方式。

3.) 它是“缓存的”,因为函数的实例被重用。

一般而言,我会远离您的第二个选项,除非这被称为 1000 / 秒之类的东西,否则您交易的复杂性不会转化为显着的性能。

如果您对性能表现感兴趣,请编写一个单元测试,在不同线程上多次调用它并使用分析器监控运行。

【讨论】:

  • 我已经进行了单元测试(更改原始方法以返回 Optionals 内的对象以避免 JIT 优化。使用 lambda 的性能稍好一些,因为 myMethod2 添加了一个额外的函数调用来获取供应商。lambda:平均= 51,069619;供应商:平均= 73,730204(纳秒)
  • @littleLouito 您不能认真地使用单元测试或类似方法进行基准测试。有太多的 JIT 优化无法正确处理它们。如果您想知道代码在“现实”(服务器上长时间运行的进程)中的执行情况,请使用JMH
  • @maaartinus 我已经使用测试来包装代码,我可以在 main() 方法中完成。我已经将每种方法重复了 1.000.000 次,其中 50.000 次作为预热,单独测量每个调用。向消费者提供从方法返回的值,这样 JIT 就不会避免任何事情。我确信测试缺少很多东西,但作为一种方法它可以提供帮助
  • @littleLouito 你所做的听起来是对的,但它可能不是。例如,您的消费者是否真的使用了该值并用它做了一些无法优化的事情?如果是这样,那么它可能比您想要测量的时间更长。你能确定,你做对了吗? JMH 的 Blackhole 可以完成这项工作,而且非常复杂。无论如何,我只是想让您了解问题(Java 基准测试比所有人预期的要困难得多)和标准解决方案 (JMH),仅此而已。
  • @maaartinus 我知道 JMH 并且读过微基准。这就是为什么我说我的测试可能做得不好。但这是我可以在五分钟内完成的 :) 感谢您的 cmets。我喜欢这个对话的方式,展示了执行出色的微基准测试是多么困难
猜你喜欢
  • 2023-01-26
  • 2013-11-07
  • 2019-02-20
  • 1970-01-01
  • 2019-07-24
  • 2018-04-08
  • 2011-10-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多