【问题标题】:Does a modern JVM optimize read only collection allocations现代 JVM 是否优化了只读集合分配
【发布时间】:2015-07-18 01:04:54
【问题描述】:

我对以下优化可能性有点好奇,但不确定如何自己验证,也许有人已经知道答案了。

我们的应用程序中有很多类似的代码。基本上它是一个有状态的处理程序(saga),由一些消息(MyStartingMessage)启动,稍后可以由一些其他消息(MyCotinueMessage)继续。因为这些StatefullHandler 有多个实例,所以我们要检查Continue 消息是否应由给定实例处理。因此,我们在处理程序中设置了一些状态,当接收到消息时,我们检查每个处理程序实例,如果消息中的状态与处理程序状态匹配,则只有消息由该处理程序实例处理。

在下面显示的示例中,某些框架将提取匹配器并检查其中是否有任何匹配接收到的继续消息实例。

因为我们每秒处理数千条此类消息,所以我很好奇 JVM 是否确实优化了实例分配(一段时间后)以不每次都创建新实例。

    class StatefullHandler implements MessageHandler {

    public void handle(final MyStartingMessage m) {
        m.setState(m.getUserId()); // used by the matchers
    }

    public void handle(final MyContinueMessage m) {
        // handle
    }

    // only returned for queries and never modified
    public Collection<MessageMatcher> matchers() {
        // message will only be handled by this instance if state matches
        // is this new operator optimized 'away' after some time??
        return ImmutableSet.of(MessageMatcher.for(MyContinueMessage.class, msg -> msg.getUserId())); 
    }
}

如果没有优化,我实际上需要这样写:

class StatefullHandler implements MessageHandler {

    private static final MATCHERS = ImmutableSet.of(
        MessageMatcher.for(MyContinueMessage.class, msg -> msg.getUserId())); 

        public void handle(final MyStartingMessage m) {
            m.setState(m.getUserId()); // used by the matchers
        }

        public void handle(final MyContinueMessage m) {
            // handle
        }

        public Collection<MessageMatcher> matchers() {
            return MATCHERS;
        }
    }

【问题讨论】:

标签: java optimization jvm


【解决方案1】:

如果你明确使用了new 关键字,JVM 就不能重用旧的对象实例,因为这会违反 Java 语言规范。首先,当您通过new 创建对象AB 时,保证A == B 将返回false。其次,保证您可以在AB 上独立同步,而无需相互等待。如果 JVM 重用旧对象,这将无法保证。因此,即使对于new Integer(1) 等最简单的情况,JVM 也无法重用它们。

在某些情况下,您可以依赖第三方库执行的缓存,但在您的特定情况下,Guava 的 ImmutableSet.of 仅将现有对象重用于空集。因此,在您的情况下,拥有 static 字段似乎是最好的解决方案。

【讨论】:

  • 好吧,它可以,如果它可以证明你从未使用过A == B 或任何其他基于身份的操作。但是你无法从 Java 代码中证明它是否有效……
【解决方案2】:

虽然 JVM 不能重用一个对象,但它可以避免一开始就创建它。

如果在内联后(即查看您的调用者,以及它的调用者等),您的对象以相同的方法生存和死亡,它可以放置在堆栈上,并可能使用转义分析消除。

在您的情况下,完全有可能不反对of(),但也消除了 lambda 对象,这不会创建任何对象。这完全取决于您的用例以及优化器是否可以消除对象创建。

我建议您使用商业分析器或飞行记录器来检查对象是否实际创建。

【讨论】:

    猜你喜欢
    • 2011-09-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-09
    相关资源
    最近更新 更多