Слайд 1Истории из жизни
одного Null Guard
Константин Рудниченко
CTO, Cadwise
Слайд 2О себе
Зарабатываю на жизнь программированием с 2005 года
Программировал еще на
.net framework 1.0
Помню С# без Generics
Слайд 3О докладе
Null Guard
Зачем
Как
Производительность
Слайд 6Null references:
The Billion-dollar mistake
Sir Charles Antony Richard Hoare, 2009
Слайд 7Наш герой: две (четыре) строчки кода
Слайд 9“У меня всё обмазано NotNullAttribute. За меня Resharper всё проверит!”
Слайд 10R#: value and nullability analysis modes
Optimistic / Pessimistic
Слайд 11“Это же мой код,
я всегда знаю, где и что
передаю!”
Слайд 13Стек-трейса не всегда достаточно
Слайд 14Стек-трейс. Пример #1.
Object reference not set to an instance of
an object
Program.Sample1(Foo foo, Boo boo) Program.Main(String[] args)
Слайд 16System.ArgumentNullException: Value cannot be null.
Parameter name: foo
Program.Sample1(Foo foo, Boo boo)
Program.Main(String[] args)
Слайд 17Стек-трейс. Пример #2
Object reference not set to an instance of
an object Samples.Sample2(IReadOnlyList`1 collection) Program.Main(String[] args)
Слайд 18Стек-трейс. Пример #3
Samples.Sample3(Foo foo) Program.Main(String[] args)
Слайд 19Стек-трейс. Пример #3. Debug
Boo.Net(Foo foo) Boo.Dot(Foo foo) Boo.Nsk(Foo foo) Boo.Hello(Foo
foo) Boo.DoSmth(Foo foo) Samples.Sample3(Foo foo) Program.Main(String[] args)
Слайд 21Компиляция и исполнение
в среде .NET
Слайд 22Компилятор C# (Roslyn)
C# → Common Intermediate Language (CIL)
Никаких оптимизаций
Слайд 23JIT-компилятор (JIT-x86, JIT-x64, RyuJIT)
CIL → native code
В runtime
Оптимизации (Release)
Method In-lining
Range-check
elimination
Loop unrolling
etc.
Слайд 24В примерах используется RyuJIT x64
Слайд 25“Ну давай, расскажи мне,
как ты будешь везде писать
эти
две строчки кода...”
Слайд 27“Поменяется стек!
И вообще всё будет тормозить!”
Слайд 30MethodImplAttribute
AggressiveInlining
NoInlining
NoOptimization
ForwardRef
InternalCall
PreserveSig
Synchronized
Unmanaged
Слайд 31Эволюция. Переименуем и размножим
ThrowIf.Argument.IsNull
ThrowIf.Variable.IsNull
ThrowIf.Field.IsNull
Слайд 33“Метод стал больше,
теперь-то точно будет тормозить!”
Слайд 34Упс! А инлайнинга-то не случилось
Слайд 40Эволюция. Guard в Generic-контейнере
Слайд 45Boxing
STACK
HEAP
i
123
int i = 123;
o
int
123
i boxed
object o = i;
Слайд 56Generics: Reference Type
Одна общая реализация
все ссылки имеют одинаковый размер
- размер указателя
какими бы ни были объекты, все операции над
указателями на них - одинаковые
Слайд 57Generics: Value Type
Для каждого Value Type отдельная реализация
int и
double имеют разный размер (4 и 8 байт). Невозможно выделить
одинаковый объем памяти на стеке
в зависимости от платформы могут использоваться разные регистры и команды
специальные оптимизации
Слайд 58“А что, если
переопределен оператор ==?”
Слайд 59А что, если переопределен оператор ==?
НИЧЕГО
Слайд 62Пустой метод vs. метод с Guard`ом
Слайд 63// * Warnings *
ZeroMeasurement
With: The method duration is indistinguishable from
the empty method duration
Without: The method duration is indistinguishable from
the empty method duration
Слайд 70JIT x86
не всегда оптимизирует boxing
Слайд 75/dotnet/coreclr: Faster null checks #21736
== null → is null
!= null
→ is object
Слайд 76Защищайся! Проверяй!
Не доверяй никому! Даже себе!
Слайд 77Константин Рудниченко
технический директор Cadwise
rudnichenko.k@gmail.com
https://t.me/krudnichenko
https://twitter.com/KRudnichenko
http://cadwise.ru