我对编译器和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)]
,但这不是我真正想要的.我希望找到一种(语言无关的)方法来确保我的代码的某些特定部分实际上按照我的预期运行,而JIT不会干扰这个过程.
另外,在创建单元测试时,我应该注意哪些典型的优化案例?
非常感谢!
别担心.不允许任何能够对您的系统产生影响的任何东西(速度除外).如果你是一个新对象,代码被调用,内存被分配,它就可以工作了.
如果你受if(false)保护,其中false是final,它可以完全优化出系统,然后它可以检测到该方法没有做任何事情并优化IT(理论上).
编辑:顺便说一句,它也足够聪明,可以确定这个方法:
newIfTrue(boolean b) { if(b) new ThisClass(); }
如果b为false,它将永远不会做任何事情,并最终发现代码B中的某一点始终为false并完全从该代码中编译此例程.
这是JIT可以在任何非托管语言中执行几乎不可能实现的内容的地方.
我想如果你担心它会被优化掉,你可能会做一些测试过度杀伤.
在静态语言中,我倾向于将编译器视为测试.如果它通过编译,那意味着某些东西(如方法).如果你没有另一个测试来运行你的默认构造函数(这将证明它不会抛出异常),你可能想要考虑为什么你首先编写默认构造函数(YAGNI和所有这些).
我知道有些人不同意我的观点,但我觉得这样的事情只会让你的测试数量膨胀,因为没有任何有用的理由,甚至通过TDD护目镜观察它.