我真的不知道很多关于编译器和JIT优化的内部,但我通常尝试用“常识”去猜测什么可以优化的,哪些不能。所以我在写一个简单的单元测试方法今天:

@Test  // [Test] in C#
public void testDefaultConstructor() {
    new MyObject();
}

此方法实际上是我所需要的。它检查默认构造存在且没有异常运行。

但后来我开始思考编译/ JIT优化的效果。可以在编译器/ JIT优化由完全消除new MyObject();声明这种方法吗?当然,这将需要确定调用图不具有副作用的其他对象,这是一个正常的构造,简单地初始化对象的内部状态的典型情况。

我相信,只有JIT将被允许进行这种优化。这可能意味着它不是我应该担心,因为正在执行的测试方法仅一次。是我的假设是否正确?

不过,我想思考的一般主题。当我想到如何避免它被优化这个方法,我想我可以assertTrue(new MyObject().toString() != null),但这是非常依赖于实际执行toString()方法,即使如此,在JIT可以确定toString()方法总是返回一个非空字符串(例如,如果实际Object.toString()被调用),并且因此优化整个分支。因此,这种方式是行不通的。

我知道,在C#中,我可以使用[MethodImpl(MethodImplOptions.NoOptimization)],但是这不是我真正想要的。我希望能找到确保我的代码一些特定部分(S)将实际运行如我所料,没有JIT在这个过程中干扰的(与语言无关)的方式。

此外,是否有任何典型案例优化我应该知道我的创建单元测试时的?

非常感谢!

有帮助吗?

解决方案

不要担心。它不允许不断优化东西,可以让你的系统的不同(除了速度)。如果新的对象,代码被调用,内存分配得到,它必须工作。

如果您有它由IF(假)的保护,其中假的最后,它可以被优化掉了系统完全的,那么它可以检测,该方法不执行任何操作,并优化它(理论上)。

编辑:顺便说一下,也可以是足够聪明来确定,该方法:

newIfTrue(boolean b) {
    if(b)
        new ThisClass();
}

将永远做什么,如果b为假,并最终弄清楚,在你的代码B中的一个点总是假的,编译这个程序出的代码完全。

这是在JIT可以做的东西,在任何非托管语言几乎是不可能。

其他提示

我想,如果你担心它得到优化掉,你可能做了一些测试矫枉过正。

在静态语言,我倾向于认为编译器作为测试的。如果通过编译,这意味着某些事情是否有(类似方法)。如果你没有其他的测试,锻炼你的默认构造函数(这将证明它不会抛出异常),你可能要想想为什么你写的是默认的构造函数在首位(YAGNI和所有)。

我知道有不同意我的观点的人,但我觉得这样的事情是只是一些做会增大你的测试数量没有有用的理由,甚至通过TDD护目镜看它。

想一想这样:

让我们假设编译器能够确定调用图形没有任何副作用(我不认为这是可能的,我依稀记得一些关于P = NP从我的CS课程)。这将优化是没有副作用的任何方法。由于大多数的测试没有,不应该有任何的副作用则编译器可以优化他们全都冲去。

在JIT仅允许执行不影响该语言的语义保证操作。从理论上说,它可以删除分配和调用到MyObject构造的如果的它可以保证调用没有副作用,不能抛出异常(不包括OutOfMemoryError)。

换句话说,如果在JIT优化呼叫你的测试,那么测试无论如何都会传递

PS:请注意,这也适用,因为你正在做的功能的测试,而不是的性能的测试。在性能测试中,以确保JIT不优化掉你测量操作,否则你的结果变得无用是很重要的。

看来,在C#中我可以这样做:

[Test]
public void testDefaultConstructor() {
    GC.KeepAlive(new MyObject());
}

AFAIU,所述GC.KeepAlive方法将不会由JIT内联,所以该代码将被保证按预期方式工作。不过,我不知道在Java中类似的结构。

它为什么重要?如果编译器/ JIT可以静态地确定任何断言都将被打(这可能引起副作用),那么你的罚款。

每个I / O是一个副作用,所以你可以把

Object obj = new MyObject();
System.out.println(obj.toString());

和你的罚款。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top