Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Performance on Android

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Kotlin Performance on Android

Александр Смирнов, Splyt

Сейчас сложно удивить фразой «мы не побоялись затащить в production новомодный Kotlin» и это здорово ведь количество приложений использующих Kotlin в качестве основного ЯП только растёт. По всегда полезно узнать про цену использования абстракции в виде Kotlin в Runtime, обсудим варианты, как улучшить картину мира. Смотреть будем с точки зрения производительности, синхронно углубляясь в особенности Android, а также подумаем, как можно использовать получившийся байткод.

Avatar for MOSDROID

MOSDROID

May 21, 2017
Tweet

More Decks by MOSDROID

Other Decks in Programming

Transcript

  1. ЩА ПОМЕРЯЕМ fun measure() : Long {
 val startTime =

    System.nanoTime()
 work()
 return System.nanoTime() - startTime
 } WRONG WAY
  2. class Test {
 
 var a = 5
 var b

    = 6
 val c = B()
 
 fun work() {
 val d = a + b
 val e = c.a + c.b
 }
 }
 
 class B(@JvmField var a: Int = 5, 
 var b: Int = 6) FIELDS
  3. L0 LINENUMBER 10 L0 ALOAD 0 GETFIELD kotlin/Test.a : I

    ALOAD 0 GETFIELD kotlin/Test.b : I IADD ISTORE 1 FIELDS var a = 5
 var b = 6
 
 val d = a + b
  4. L1 LINENUMBER 11 L1 ALOAD 0 GETFIELD kotlin/Test.c : Lkotlin/B;

    GETFIELD kotlin/B.a : I ALOAD 0 GETFIELD kotlin/Test.c : Lkotlin/B; INVOKEVIRTUAL kotlin/B.getB ()I IADD ISTORE 2 FIELDS val e = c.a + c.b
 
 class B(@JvmField var a: Int = 5, 
 var b: Int = 6)
  5. NOT STATIC companion object {
 var k = 5
 


    fun work2() : Int = 42 } val i = k + work2() L2 LINENUMBER 21 L2 GETSTATIC kotlin/Test.Companion : Lkotlin/Test$Companion; INVOKEVIRTUAL kotlin/Test$Companion.getK ()I GETSTATIC kotlin/Test.Companion : Lkotlin/Test$Companion; INVOKEVIRTUAL kotlin/Test$Companion.work2 ()I IADD ISTORE 3
  6. NOT STATIC private static int k = 5;
 public static

    final Test.Companion Companion = new Test.Companion((DefaultConstructorMarker)null); 
 public static final class Companion {
 public final int getK() { return Test.k;}
 
 public final void setK(int var1) {
 Test.k = var1;
 }
 
 public final int work2() { return 42; }
 
 private Companion() { }
 
 // $FF: synthetic method
 public Companion(DefaultConstructorMarker $constructor_marker) { this(); }
 }
  7. NOT STATIC val i = k + work2() companion object

    { @JvmField
 var k = 5
 @JvmStatic
 fun work2() : Int = 42 } private static int k = 5;
 public static final Test.Companion Companion = new Test.Companion((DefaultConstructorMarker)null); 
 public static final class Companion {
 @JvmStatic
 public final int work2() { return 42; }
 
 private Companion() {}
 
 // $FF: synthetic method
 public Companion(DefaultConstructorMarker $constructor_marker) { this(); } }
  8. NOT STATIC val i = k + work2() companion object

    { @JvmField
 var k = 5
 @JvmStatic
 fun work2() : Int = 42 } L2 LINENUMBER 21 L2 GETSTATIC kotlin/Test.k : I GETSTATIC kotlin/Test.Companion : Lkotlin/Test$Companion; INVOKEVIRTUAL kotlin/Test$Companion.work2 ()I IADD ISTORE 3
  9. REAL STATIC !? object A {
 fun test() = 53


    } L3 LINENUMBER 23 L3 GETSTATIC kotlin/A.INSTANCE : Lkotlin/A; INVOKEVIRTUAL kotlin/A.test ()I POP
  10. NULLABILITY fun test(first: String, second: String?) : String {
 second

    ?: return first
 
 return "$first $second"
 }
  11. NULLABILITY fun test(first: String, second: String?) : String {
 second

    ?: return first
 
 return "$first $second"
 } @NotNull
 public final String test(@NotNull String first, @Nullable String second) {
 Intrinsics.checkParameterIsNotNull(first, "first");
 return second != null ? (first + " " + second) : first;
 }
  12. var a = 5
 var b = 6
 var bOption

    : Int? = 6 PRIMITIVES private int a = 5;
 private int b = 6;
 @Nullable private Integer bOption = Integer.valueOf(6);
  13. AUTOBOXING val a: String? = null
 var b = a?.isBlank()

    == true if (a != null && a.isBlank()) true else false
  14. AUTOBOXING val a: String? = null
 var b = a?.isBlank()

    == true String a = (String)null;
 boolean b = Intrinsics.areEqual(a != null ? Boolean.valueOf(StringsKt.isBlank((CharSequence)a)) : null, Boolean.valueOf(true)); if (a != null && a.isBlank()) true else false
  15. LOOPS inline fun <reified T> List<T>.foreach(crossinline action: (T) -> Unit):

    Unit {
 val size = size
 var i = 0 
 while (i < size) {
 action(get(i))
 i++
 }
 } list.foreach {
 work(it * 2)
 }
  16. RANGES inline fun <reified T> List<T>.foreach(crossinline action: (T) -> Unit):

    Unit {
 val size = size 
 for(i in 0..size) {
 work(i * 2)
 } 
 }
  17. INTRINSICS public final class Test {
 @NotNull
 public final String

    concat(@NotNull String first,
 @NotNull String second) {
 Intrinsics.checkParameterIsNotNull(first, "first");
 Intrinsics.checkParameterIsNotNull(second, "second");
 return first + " " + second;
 }
 }
  18. INTRINSICS public final class Test {
 @NotNull
 public final String

    concat(@NotNull String first, 
 @NotNull String second) {
 return first + " " + second;
 }
 } kotlinc -Xno-call-assertions -Xno-param-assertions Test.kt
  19. BENCHMARKS 1.2 ГГЦ 4 ЯДРА – 1 ГБ ОЗУ –

    4.4.2 – 480X854 HUAWEI Y54 I-U02 ~25% ПРОФИТА ПОДРОБНОСТИ В СТАТЬЕ, ПОМНИМ ПРО МАГИЮ
 ПРОЦЕНТОВ НА МАЛЕНЬКИХ ЧИСЛАХ
  20. BENCHMARKS 2.1 ГГЦ + 1.5 ГГЦ – 3 ГБ ОЗУ

    – 7.0 – 2560X1440 SAMSUNG GALAXY S6 ~40% ПРОФИТА ПОДРОБНОСТИ В СТАТЬЕ, ПОМНИМ ПРО МАГИЮ
 ПРОЦЕНТОВ НА МАЛЕНЬКИХ ЧИСЛАХ
  21. BENCHMARKS 2.15 ГГЦ + 1.6 ГГЦ– 4 ГБ ОЗУ –

    7.1.2 – 1920X1080 GOOGLE PIXEL БЕЗ ИЗМЕНЕНИЙ ПОДРОБНОСТИ В СТАТЬЕ, ПОМНИМ ПРО МАГИЮ
 ПРОЦЕНТОВ НА МАЛЕНЬКИХ ЧИСЛАХ
  22. BENCHMARKS 1.3 ГГЦ– 1 ГБ ОЗУ – 4.4.2 – 960X540

    ONN K7 SUNNY ~20% ПРОФИТА ПОДРОБНОСТИ В СТАТЬЕ, ПОМНИМ ПРО МАГИЮ
 ПРОЦЕНТОВ НА МАЛЕНЬКИХ ЧИСЛАХ
  23. ИТОГО БЫСТРОДЕЙСТВИЕ ВАЖНО ТОЛЬКО НА UI ПОТОКЕ ОЧЕНЬ КРИТИЧНО ТОЛЬКО

    В ONMEASURE - ONLAYOUT - ONDRAW ПРАКТИЧЕСКИ ВСЕГДА МОЖНО НАПИСАТЬ С ИДЕНТИЧНОЙ СКОРОСТЬЮ РАБОТЫ ПРЕЖДЕВРЕМЕННЫЕ ОПТИМИЗАЦИИ ЗЛО