IL2CPPでsealedを付けても速くならない
Unityでclassを定義するときにsealedを付けると高速化すると言う話があります。この話の大本のソースはIL2CPP Optimizations: Devirtualizationだと思います。
では実際にどのくらい速くなるのか計測するために以下のコードで試してみました。記事通りならInvokeNonSealedよりもInvokeSealedの方が高速なはずです。
using NUnit.Framework;
using Unity.PerformanceTesting;
public abstract class Parent
{
public abstract string Method();
}
public class NonSealedChild : Parent
{
public override string Method() => nameof(NonSealedChild);
}
public sealed class SealedChild : Parent
{
public override string Method() => nameof(SealedChild);
}
public class PerformanceTest
{
[Test, Performance]
public void InvokeNonSealed()
{
var c = new NonSealedChild();
Measure.Method(() => { c.Method(); })
.WarmupCount(10)
.MeasurementCount(100)
.IterationsPerMeasurement(100000)
.Run();
}
[Test, Performance]
public void InvokeSealed()
{
var c = new SealedChild();
Measure.Method(() => { c.Method(); })
.WarmupCount(10)
.MeasurementCount(100)
.IterationsPerMeasurement(100000)
.Run();
}
}
Unity2020.3.17での計測結果は以下になります。ほとんど変わりません。
IL2CPPでビルドされたC++のコードを直接確認しても、どちらもVirtFuncInvoker0を使って呼ばれているので速くなる理由がありません。
どうしてこうなったかというと、現在のUnityではDevirtualizationが行われていないためです。Unityの方が明言しています。
sealedを付けるべきか?
ややこしいことに、UnityのIL2CPPでは高速化しませんが.NET6では高速化されます。Unityでは.NET5を飛ばして.NET6をサポートするつもりではあるようです。なので将来的にはUnityでも高速化される可能性があります。将来のためにも可能な箇所ではsealedを付けておくのが良いと思います。