Slide 1

Slide 1 text

Jake Wharton Exploring Java Hidden Costs

Slide 2

Slide 2 text

2? 0? 1? How many methods? class Example {
 }"

Slide 3

Slide 3 text

How many methods? class Example {
 }" 2? 0! 1?

Slide 4

Slide 4 text

How many methods? $ echo "class Example {
 }" > Example.java 2? 0! 1?

Slide 5

Slide 5 text

How many methods? $ echo "class Example {
 }" > Example.java $ javac Example.java 2? 0! 1?

Slide 6

Slide 6 text

How many methods? $ echo "class Example {
 }" > Example.java $ javac Example.java $ javap Example.class 2? 0! 1?

Slide 7

Slide 7 text

How many methods? $ echo "class Example {
 }" > Example.java $ javac Example.java $ javap Example.class class Example { Example(); } 2? 0! 1?

Slide 8

Slide 8 text

$ echo "class Example {
 }" > Example.java $ javac Example.java $ javap Example.class class Example { Example(); } How many methods? $ echo "class Example {
 }" > Example.java $ javac Example.java $ javap Example.class class Example { Example(); } 2? 0! 1? How many methods? 0! 1? 2?

Slide 9

Slide 9 text

$ echo "class Example {
 }" > Example.java $ javac Example.java $ javap Example.class class Example { Example(); } How many methods? 2? 0! 1!

Slide 10

Slide 10 text

$ dx --dex --output=example.dex Example.class How many methods? 2? 0! 1!

Slide 11

Slide 11 text

$ dx --dex --output=example.dex Example.class $ dexdump -f example.dex How many methods? 2? 0! 1!

Slide 12

Slide 12 text

$ dx --dex --output=example.dex Example.class $ dexdump -f example.dex Opened 'example.dex', DEX version '035' DEX file header: magic : 'dex\n035\0' checksum : b4e92dde signature : f51f...a6a1 file_size : 436 header_size : 112 link_size : 0 link_off : 0 (0x000000) string_ids_size : 5 string_ids_off : 112 (0x000070) type_ids_size : 3 type_ids_off : 132 (0x000084) proto_ids_size : 1 proto_ids_off : 144 (0x000090) field_ids_size : 0 field_ids_off : 0 (0x000000) method_ids_size : 2 method_ids_off : 156 (0x00009c) class_defs_size : 1 class_defs_off : 172 (0x0000ac) data_size : 232 data_off : 204 (0x0000cc) How many methods? 2? 0! 1!

Slide 13

Slide 13 text

$ dx --dex --output=example.dex Example.class $ dexdump -f example.dex Opened 'example.dex', DEX version '035' DEX file header: magic : 'dex\n035\0' checksum : b4e92dde signature : f51f...a6a1 file_size : 436 header_size : 112 link_size : 0 link_off : 0 (0x000000) string_ids_size : 5 string_ids_off : 112 (0x000070) type_ids_size : 3 type_ids_off : 132 (0x000084) proto_ids_size : 1 proto_ids_off : 144 (0x000090) field_ids_size : 0 field_ids_off : 0 (0x000000) method_ids_size : 2 method_ids_off : 156 (0x00009c) class_defs_size : 1 class_defs_off : 172 (0x0000ac) data_size : 232 data_off : 204 (0x0000cc) How many methods? $ dx --dex --output=example.dex Example.class $ dexdump -f example.dex Opened 'example.dex', DEX version '035' DEX file header: magic : 'dex\n035\0' checksum : b4e92dde signature : f51f...a6a1 file_size : 436 header_size : 112 link_size : 0 link_off : 0 (0x000000) string_ids_size : 5 string_ids_off : 112 (0x000070) type_ids_size : 3 type_ids_off : 132 (0x000084) proto_ids_size : 1 proto_ids_off : 144 (0x000090) field_ids_size : 0 field_ids_off : 0 (0x000000) method_ids_size : 2 method_ids_off : 156 (0x00009c) class_defs_size : 1 class_defs_off : 172 (0x0000ac) data_size : 232 data_off : 204 (0x0000cc) 2? 0! 1!

Slide 14

Slide 14 text

$ dex-method-list example.dex How many methods? 2? 0! 1!

Slide 15

Slide 15 text

$ dex-method-list example.dex Example () java.lang.Object () How many methods? 2? 0! 1!

Slide 16

Slide 16 text

$ dex-method-list example.dex Example () java.lang.Object () $ javap -c Example.class How many methods? 2? 0! 1!

Slide 17

Slide 17 text

$ dex-method-list example.dex Example () java.lang.Object () $ javap -c Example.class class Example { Example(); Code: 0: aload_0 1: invokespecial #1 //java/lang/Object."":()V 4: return } How many methods? 2? 0! 1!

Slide 18

Slide 18 text

$ dex-method-list example.dex Example () java.lang.Object () $ javap -c Example.class class Example { Example(); Code: 0: aload_0 1: invokespecial #1 //java/lang/Object."":()V 4: return } How many methods? 2? 0! 1! $ dex-method-list example.dex Example () java.lang.Object () $ javap -c Example.class class Example { Example(); Code: 0: aload_0 1: invokespecial #1 //java/lang/Object."":()V 4: return } 2? 0! 1! How many methods?

Slide 19

Slide 19 text

$ dex-method-list example.dex Example () java.lang.Object () $ javap -c Example.class class Example { Example(); Code: 0: aload_0 1: invokespecial #1 //java/lang/Object."":()V 4: return } How many methods? 2! 0! 1!

Slide 20

Slide 20 text

How many methods? 2 0 1 class Example {
 }" 0 declared methods 0 in the source file

Slide 21

Slide 21 text

How many methods? 2 1 class Example {
 }" 0 declared methods 0 in the source file 0 and only humans care

Slide 22

Slide 22 text

How many methods? 2 class Example {
 }" 0 declared methods 1 1 compiled method 0 in the class file

Slide 23

Slide 23 text

How many methods? 2 class Example {
 }" 0 declared methods 1 compiled method 2 referenced methods 0 in the dex file

Slide 24

Slide 24 text

How many methods? class Example {
 }3 0 declared methods 1 compiled method 2 referenced methods 0 in the dex file 0 for the true "method count"

Slide 25

Slide 25 text

// Outer.java public class OuterA{1 private class Example {2 }3
 }4

Slide 26

Slide 26 text

// ItemsView.java public class ItemsViewA{1 private class ItemsAdapter {2 }3
 }4 Outer Outer Example

Slide 27

Slide 27 text

// ItemsView.java public class ItemsView { private class ItemsAdapter { }
 }" $ javac ItemsView.java

Slide 28

Slide 28 text

// ItemsView.java public class ItemsView { private class ItemsAdapter { }
 }" $ javac ItemsView.java $ ls ItemsView.class ItemsView.java ItemsView$ItemsAdapter.class

Slide 29

Slide 29 text

// ItemsView.java public class ItemsView { private class ItemsAdapter { }
 }" 
 $ javap ItemsView public class ItemsView { public ItemsView(); }

Slide 30

Slide 30 text

// ItemsView.java public class ItemsView { private class ItemsAdapter { }G
 }" 
 $ javap 'ItemsView$ItemsAdapter' class ItemsView$ItemsAdapter { ItemsView$ItemsAdapter(); } 
 // ItemsAdapter.java

Slide 31

Slide 31 text

// ItemsView.java public class ItemsView { private class ItemsAdapter { }G
 }" 
 // ItemsAdapter.java

Slide 32

Slide 32 text

// ItemsView.java public class ItemsView {
 }" // ItemsAdapter.java class ItemsAdapter { }G

Slide 33

Slide 33 text

// ItemsView.java public class ItemsView {
 }" // ItemsView$ItemsAdapter.java class ItemsView$ItemsAdapter { }G

Slide 34

Slide 34 text

// ItemsView.java public class ItemsView { private class ItemsAdapter { }G
 }" 
 // ItemsView$ItemsAdapter.java ItemsView$

Slide 35

Slide 35 text

// ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }L
 
 private class ItemsAdapter {
 }G
 }"

Slide 36

Slide 36 text

// ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }L
 
 private class ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }H
 }G
 }" 
 
 
 
 
 // ItemsView$ItemsAdapter.java ItemsView$

Slide 37

Slide 37 text

// ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }L
 
 private class ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }H
 }G
 }"

Slide 38

Slide 38 text

// ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }L
 }" 
 // ItemsView$ItemsAdapter.java class ItemsView$ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }H
 }G 
 
 
 
 
 private

Slide 39

Slide 39 text

// ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }L
 }" 
 // ItemsView$ItemsAdapter.java class ItemsView$ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }H
 }G 
 
 
 
 
 private // ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }
 }" 
 // ItemsView$ItemsAdapter.java class ItemsView$ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }
 }

Slide 40

Slide 40 text

// ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }L
 
 private class ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }H
 }G
 }"

Slide 41

Slide 41 text

$ javac -bootclasspath android-sdk/platforms/android-24/android.jar \ ItemsView.java $ javap -c 'ItemsView$ItemsAdapter'

Slide 42

Slide 42 text

$ javac -bootclasspath android-sdk/platforms/android-24/android.jar \ ItemsView.java $ javap -c 'ItemsView$ItemsAdapter' class ItemsView$ItemAdapter { void bindItem(android.widget.TextView, java.lang.String); Code: 0: aload_1 1: aload_2 2: invokestatic #3 // Method ItemsView.access$000:… 5: invokevirtual #4 // Method TextView.setText:… 8: return }

Slide 43

Slide 43 text

$ javac -bootclasspath android-sdk/platforms/android-24/android.jar \ ItemsView.java $ javap -c 'ItemsView$ItemsAdapter' class ItemsView$ItemAdapter { void bindItem(android.widget.TextView, java.lang.String); Code: 0: aload_1 1: aload_2 2: invokestatic #3 // Method ItemsView.access$000:… 5: invokevirtual #4 // Method TextView.setText:… 8: return }

Slide 44

Slide 44 text

$ javap -p ItemsView

Slide 45

Slide 45 text

$ javap -p ItemsView123 class ItemsView { ItemsView(); private static java.lang.String displayText(…); static java.lang.String access$000(…); } -c

Slide 46

Slide 46 text

$ javap -p -c ItemsView123

Slide 47

Slide 47 text

$ javap -p -c ItemsView123 class ItemsView { ItemsView(); Code: private static java.lang.String displayText(…); Code: static java.lang.String access$000(…); Code: 0: aload_0 1: invokestatic #1 // Method displayText:… 4: areturn }

Slide 48

Slide 48 text

$ javap -p -c ItemsView class ItemsView { ItemsView(); Code: private static java.lang.String displayText(…); Code: static java.lang.String access$000(…); Code: 0: aload_0 1: invokestatic #1 // Method displayText:… 4: areturn }

Slide 49

Slide 49 text

// ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }B
 }A 
 // ItemsView$ItemsAdapter.java class ItemsView$ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }b
 }a

Slide 50

Slide 50 text

// ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }B static String access$000(String item) {
 return displayText(item);
 }C
 }A 
 // ItemsView$ItemsAdapter.java class ItemsView$ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }b
 }a // ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }B static String access$000(String item) {
 return displayText(item);
 }C
 }A 
 // ItemsView$ItemsAdapter.java class ItemsView$ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }b
 }a

Slide 51

Slide 51 text

// ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }B static String access$000(String item) {
 return displayText(item);
 }C
 }A 
 // ItemsView$ItemsAdapter.java class ItemsView$ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.access$000(item));
 }b
 }a // ItemsView.java public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }B static String access$000(String item) {
 return displayText(item);
 }C
 }A 
 // ItemsView$ItemsAdapter.java class ItemsView$ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.access$000(item));
 }b
 }a 
 
 
 
 
 
 
 
 displayText

Slide 52

Slide 52 text

$ dx --dex --output=example.dex *.class $ dex-method-list example.dex

Slide 53

Slide 53 text

$ dx --dex --output=example.dex *.class $ dex-method-list example.dex ItemsView () ItemsView access$000(String) → String ItemsView displayText(String) → String ItemsView$ItemsAdapter (ItemsView) ItemsView$ItemsAdapter bindItem(TextView, String) android.widget.TextView setText(CharSequence) java.lang.Object ()

Slide 54

Slide 54 text

$ dx --dex --output=example.dex *.class $ dex-method-list example.dex ItemsView () ItemsView access$000(String) → String ItemsView displayText(String) → String ItemsView$ItemsAdapter (ItemsView) ItemsView$ItemsAdapter bindItem(TextView, String) android.widget.TextView setText(CharSequence) java.lang.Object ()

Slide 55

Slide 55 text

$ java -jar android-sdk/build-tools/24.0.1/jack.jar \ -cp android-sdk/platforms/android-24/android.jar \ --output-dex . \ ItemsView.java $ dex-method-list classes.dex

Slide 56

Slide 56 text

$ java -jar android-sdk/build-tools/24.0.1/jack.jar \ -cp android-sdk/platforms/android-24/android.jar \ --output-dex . \ ItemsView.java $ dex-method-list classes.dex ItemsView -wrap0(String) → String ItemsView () ItemsView displayText(String) → String ItemsView$ItemsAdapter (ItemsView) ItemsView$ItemsAdapter bindItem(TextView, String) android.widget.TextView setText(CharSequence) java.lang.Object ()

Slide 57

Slide 57 text

$ java -jar android-sdk/build-tools/24.0.1/jack.jar \ -cp android-sdk/platforms/android-24/android.jar \ --output-dex . \ ItemsView.java $ dex-method-list classes.dex ItemsView -wrap0(String) → String ItemsView () ItemsView displayText(String) → String ItemsView$ItemsAdapter (ItemsView) ItemsView$ItemsAdapter bindItem(TextView, String) android.widget.TextView setText(CharSequence) java.lang.Object ()

Slide 58

Slide 58 text

$ echo "-dontobfuscate -keep class ItemsView$ItemsAdapter { void bindItem(...); } " > rules.txt $ java -jar proguard-base-5.2.1.jar \ -include rules.txt \ -injars . \ -outjars example-proguard.jar \ -libraryjars android-sdk/platforms/android-24/android.jar $ dex-method-list example-proguard.jar $ dex-method-list example-proguard.jar

Slide 59

Slide 59 text

$ echo "-dontobfuscate -keep class ItemsView$ItemsAdapter { void bindItem(...); } " > rules.txt $ java -jar proguard-base-5.2.1.jar \ -include rules.txt \ -injars . \ -outjars example-proguard.jar \ -libraryjars android-sdk/platforms/android-24/android.jar $ dex-method-list example-proguard.jar ItemsView access$000(String) → String ItemsView$ItemsAdapter bindItem(TextView, String) android.widget.TextView setText(CharSequence)

Slide 60

Slide 60 text

$ dex-method-list example-proguard.jar ItemsView access$000(String) → String ItemsView$ItemsAdapter bindItem(TextView, String) android.widget.TextView setText(CharSequence)

Slide 61

Slide 61 text

$ dex-method-list example-proguard.jar ItemsView () ItemsView access$000(String) → String ItemsView$ItemsAdapter (ItemsView) ItemsView$ItemsAdapter bindItem(TextView, String) android.widget.TextView setText(CharSequence) java.lang.Object ()

Slide 62

Slide 62 text

$ dex-method-list example-proguard.jar ItemsView () ItemsView access$000(String) → String ItemsView$ItemsAdapter (ItemsView) ItemsView$ItemsAdapter bindItem(TextView, String) android.widget.TextView setText(CharSequence) java.lang.Object ()

Slide 63

Slide 63 text

$ unzip example-proguard.jar $ unzip example-proguard.jar $ javap -c ItemsView

Slide 64

Slide 64 text

$ unzip example-proguard.jar $ javap -c ItemsView public final class ItemsView { static java.lang.String access$000(java.lang.String); Code: 0: ldc #1 // String "" 2: areturn }

Slide 65

Slide 65 text

class MyActivity extends Activity {
 @Override protected void onCreate(Bundle state) {
 super.onCreate(state); 
 setContentView(R.layout.whatever);
 findViewById(R.id.button).setOnClickListener( new OnClickListener() {
 @Override public void onClick(View view) {
 // Hello!
 }
 });
 }
 }

Slide 66

Slide 66 text

class MyActivity extends Activity {
 @Override protected void onCreate(Bundle state) {
 super.onCreate(state); 
 setContentView(R.layout.whatever);
 findViewById(R.id.button).setOnClickListener( new OnClickListener() {
 @Override public void onClick(View view) {
 // Hello!
 }C
 });
 }B
 }A

Slide 67

Slide 67 text

class MyActivity extends Activity {
 @Override protected void onCreate(Bundle state) {
 super.onCreate(state); 
 setContentView(R.layout.whatever);
 findViewById(R.id.button).setOnClickListener( new OnClickListener() {
 @Override public void onClick(View view) {
 doSomething(); }C
 });
 }B private void doSomething() {
 // ...
 }D
 }A 
 
 
 
 
 // Hello!

Slide 68

Slide 68 text

class MyActivity extends Activity {
 private int count; 
 @Override protected void onCreate(Bundle state) {
 super.onCreate(state); 
 setContentView(R.layout.whatever);
 findViewById(R.id.button).setOnClickListener( new OnClickListener() {
 @Override public void onClick(View view) {
 count = 0;
 ++count;
 --count;
 count++;
 count--;
 Log.d("Count", "= " + count); }C
 });
 }B
 }A 
 
 
 
 
 
 doSomething(); 
 
 private void doSomething() {
 // ...
 }D


Slide 69

Slide 69 text

class MyActivity extends Activity {
 private int count; 
 @Override protected void onCreate(Bundle state) {
 super.onCreate(state); 
 setContentView(R.layout.whatever);
 findViewById(R.id.button).setOnClickListener( new OnClickListener() {
 @Override public void onClick(View view) {
 count = 0;
 ++count;
 --count;
 count++;
 count--;
 Log.d("Count", "= " + count); }C
 });
 }B
 }A

Slide 70

Slide 70 text

class MyActivity extends Activity {
 private int count; 
 @Override protected void onCreate(Bundle state) {
 super.onCreate(state); 
 setContentView(R.layout.whatever);
 findViewById(R.id.button).setOnClickListener( new OnClickListener() {
 @Override public void onClick(View view) {
 count = 0;
 ++count;
 --count;
 count++;
 count--;
 Log.d("Count", "= " + count); }C
 });
 }B
 }A

Slide 71

Slide 71 text

$ javac -bootclasspath android-sdk/platforms/android-24/android.jar \ MyActivity.java $ javap MyActivity

Slide 72

Slide 72 text

$ javac -bootclasspath android-sdk/platforms/android-24/android.jar \ MyActivity.java $ javap MyActivity class MyActivity extends android.app.Activity { MyActivity(); protected void onCreate(android.os.Bundle); static int access$002(MyActivity, int); static int access$004(MyActivity); static int access$006(MyActivity); static int access$008(MyActivity); static int access$010(MyActivity); static int access$000(MyActivity); }

Slide 73

Slide 73 text

$ javac -bootclasspath android-sdk/platforms/android-24/android.jar \ MyActivity.java $ javap MyActivity class MyActivity extends android.app.Activity { MyActivity(); protected void onCreate(android.os.Bundle); static int access$002(MyActivity, int); static int access$004(MyActivity); static int access$006(MyActivity); static int access$008(MyActivity); static int access$010(MyActivity); static int access$000(MyActivity); } // count = 0 write // ++count preinc // --count predec // count++ postinc // count-- postdec // count read

Slide 74

Slide 74 text

$ adb shell mkdir /mnt/sdcard/apks $ adb shell cmd package list packages -3 -f \ | cut -c 9- \ | sed 's|=| /mnt/sdcard/apks/|' \ | xargs -t -L1 adb shell cp $ adb pull /mnt/sdkcard/apks

Slide 75

Slide 75 text

accessors.sh #!/bin/bash
 set -e
 
 METHODS=$(dex-method-list $1 | \grep 'access\$')
 ACCESSORS=$(echo "$METHODS" | wc -l | xargs)
 METHOD_AND_READ=$(echo "$METHODS" | egrep 'access\$\d+00\(' | wc -l | xargs)
 WRITE=$(echo "$METHODS" | egrep 'access\$\d+02\(' | wc -l | xargs)
 PREINC=$(echo "$METHODS" | egrep 'access\$\d+04\(' | wc -l | xargs)
 PREDEC=$(echo "$METHODS" | egrep 'access\$\d+06\(' | wc -l | xargs)
 POSTINC=$(echo "$METHODS" | egrep 'access\$\d+08\(' | wc -l | xargs)
 POSTDEC=$(echo "$METHODS" | egrep 'access\$\d+10\(' | wc -l | xargs)
 OTHER=$(($ACCESSORS - $METHOD_AND_READ - $WRITE - $PREINC - $PREDEC - $POSTINC - $POSTDEC))
 
 NAME=$(basename $1)
 
 echo -e "$NAME\t$ACCESSORS\t$READ\t$WRITE\t$PREINC\t$PREDEC\t$POSTINC\t$POSTDEC\t$OTHER"

Slide 76

Slide 76 text

$ column -t -s $'\t' \ <(echo -e "NAME\tTOTAL\tMETHOD/READ\tWRITE\tPREINC\tPREDEC\tPOSTINC\tPOSTDEC\tOTHER" \ && find apks -type f | \ xargs -L1 ./accessors.sh | \ sort -k2,2nr) Warning: This may take a while to run!

Slide 77

Slide 77 text

$ column -t -s $'\t' \ <(echo -e "NAME\tTOTAL\tMETHOD/READ\tWRITE\tPREINC\tPREDEC\tPOSTINC\tPOSTDEC\tOTHER" \ && find apks -type f | \ xargs -L1 ./accessors.sh | \ sort -k2,2nr) NAME TOTAL METHOD/READ WRITE PREINC PREDEC POSTINC POSTDEC OTHER com.amazon.avod.thirdpartyclient 5545 4963 506 0 0 9 5 62 com.amazon.kindle 5245 4399 789 0 0 11 4 42 com.amazon.mShop.android 4774 4091 593 2 0 42 6 40 com.audible.application 4357 3782 526 0 0 7 1 41 com.waze 4269 3544 675 0 0 18 4 28 com.amazon.mShop.android.shopping 3587 2968 536 3 0 38 5 37 me.lyft.android 3330 3111 200 0 1 2 1 15 com.nhl.gc1112.free 2796 2446 316 1 2 9 5 17 com.etrade.mobilepro.activity 2611 2327 273 0 0 2 1 8 air.com.nbcuni.com.nbcsports.liveextra 2448 2120 305 0 0 14 2 7 com.untappdllc.app 2314 2000 247 1 0 6 0 60 com.paypal.android.p2pmobile 2066 1771 286 1 0 2 0 6 com.google.android.apps.giant 1967 1747 199 0 0 6 3 12 com.netflix.mediaclient 1963 1642 294 1 0 9 2 15 com.stackexchange.marvin 1842 1386 260 0 0 6 2 188 net.flixster.android 1836 1583 239 0 0 6 2 6 com.Slack 1801 1571 215 0 0 5 2 8 com.showtime.showtimeanytime 1727 1450 250 0 0 4 4 19 com.google.android.apps.cloudconsole 1643 1464 168 0 0 1 2 8 com.eventbrite.attendee 1529 1368 147 0 0 2 0 12 org.videolan.vlc 1358 1163 151 0 0 2 1 41 com.imdb.mobile 1353 897 92 1 0 3 1 359 com.robinhood.android 1239 1036 149 0 0 4 0 50 com.twitter.android 1088 957 117 0 0 5 0 9

Slide 78

Slide 78 text

No content

Slide 79

Slide 79 text

public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }L
 
 private class ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }H
 }G
 }"

Slide 80

Slide 80 text

public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }L
 
 private class ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }H
 }G
 }"

Slide 81

Slide 81 text

public class ItemsView {
 private static String displayText(String item) {
 return ""; // TODO
 }L
 
 private class ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }H
 }G
 }"

Slide 82

Slide 82 text

public class ItemsView {
 static String displayText(String item) {
 return ""; // TODO
 }L
 
 private class ItemsAdapter {
 void bindItem(TextView tv, String item) {
 tv.setText(ItemsView.displayText(item));
 }H
 }G
 }"

Slide 83

Slide 83 text

interface Callback {
 void call(T value);
 } 
 
 
 class StringCallback implements Callback {
 @Override public void call(String value) {
 System.out.println(value);
 }
 } // Callbacks.java

Slide 84

Slide 84 text

$ javac Callbacks.java $ javap StringCallback

Slide 85

Slide 85 text

$ javac Callbacks.java $ javap StringCallback class StringCallback implements Callback { StringCallback(); public void call(java.lang.String); public void call(java.lang.Object); } -c

Slide 86

Slide 86 text

$ javap -c StringCallback

Slide 87

Slide 87 text

$ javap -c StringCallback class StringCallback implements Callback { StringCallback(); Code: public void call(java.lang.String); Code: public void call(java.lang.Object); Code: 0: aload_0 1: aload_1 2: checkcast #4 // class java/lang/String 5: invokevirtual #5 // Method call:(Ljava/lang/String;)V 8: return }

Slide 88

Slide 88 text

$ javap -c StringCallback class StringCallback implements Callback { StringCallback(); Code: public void call(java.lang.String); Code: public void call(java.lang.Object); Code: 0: aload_0 1: aload_1 2: checkcast #4 // class java/lang/String 5: invokevirtual #5 // Method call:(Ljava/lang/String;)V 8: return }

Slide 89

Slide 89 text

// Providers.java 
 
 
 
 
 
 class ViewProvider implements Provider {
 @Override public View get(Context context) {
 return new View(context);
 }
 } 
 
 interface Provider {
 T get(Context context);
 }

Slide 90

Slide 90 text

$ javac -bootclasspath android-sdk/platforms/android-24/android.jar \ Example.java $ javap -c ViewProvider class ViewProvider implements Provider { ViewProvider(); Code: public android.view.View get(android.content.Context); Code: public java.lang.Object get(android.content.Context); Code: 0: aload_0 1: aload_1 2: invokevirtual #4 // Method get:(…)Landroid/view/View; 5: areturn }

Slide 91

Slide 91 text

$ javac -bootclasspath android-sdk/platforms/android-24/android.jar \ Example.java $ javap -c ViewProvider class ViewProvider implements Provider { ViewProvider(); Code: public android.view.View get(android.content.Context); Code: public java.lang.Object get(android.content.Context); Code: 0: aload_0 1: aload_1 2: invokevirtual #4 // Method get:(…)Landroid/view/View; 5: areturn }

Slide 92

Slide 92 text

// Providers.java 
 
 
 
 
 
 class ViewProvider implements Provider {
 @Override public View get(Context context) {
 return new View(context);
 }2
 }3 
 
 interface Provider {
 T get(Context context);
 }

Slide 93

Slide 93 text

class ViewProvider implements Provider {
 @Override public View get(Context context) {
 return new View(context);
 }2
 }3 class TextViewProvider extends ViewProvider {
 @Override public TextView get(Context context) {
 return new TextView(context);
 }
 }

Slide 94

Slide 94 text

class ViewProvider implements Provider {
 @Override public View get(Context context) {
 return new View(context);
 }
 } class TextViewProvider extends ViewProvider {
 @Override public TextView get(Context context) {
 return new TextView(context);
 }
 }

Slide 95

Slide 95 text

$ javap TextViewProvider class TextViewProvider extends ViewProvider { TextViewProvider(); public android.widget.TextView get(android.content.Context); public android.view.View get(android.content.Context); public java.lang.Object get(android.content.Context); }

Slide 96

Slide 96 text

#!/usr/bin/python
 
 import os
 import subprocess
 import sys
 
 list = subprocess.check_output(["dex-method-list", sys.argv[1]])
 
 class_info_by_name = {}
 
 for item in list.split('\n'):
 first_space = item.find(' ')
 open_paren = item.find('(')
 close_paren = item.find(')')
 last_space = item.rfind(' ')
 
 class_name = item[0:first_space]
 method_name = item[first_space + 1:open_paren]
 params = [param for param in item[open_paren + 1:close_paren].split(', ') if len(param) > 0]
 return_type = item[last_space + 1:]
 if last_space < close_paren:
 return_type = 'void'
 
 # print class_name, method_name, params, return_type
 
 if class_name not in class_info_by_name:
 class_info_by_name[class_name] = {}
 class_info = class_info_by_name[class_name]
 
 if method_name not in class_info:
 class_info[method_name] = []
 method_info_by_name = class_info[method_name]
 
 method_info_by_name.append({
 'params': params,
 'return': return_type
 })
 
 count = 0
 for class_name, class_info in class_info_by_name.items():
 for method_name, method_info_by_name in class_info.items():
 for method_info in method_info_by_name:
 for other_method_info in method_info_by_name:
 if method_info == other_method_info:
 continue # Do not compare against self.
 params = method_info['params']
 other_params = other_method_info['params']
 if len(params) != len(other_params):
 continue # Do not compare different numbered parameter lists.
 
 match = True
 erased = False
 for idx, param in enumerate(params):
 other_param = other_params[idx]
 if param != 'Object' and not param[0].islower() and other_param == 'Object':
 erased = True
 elif param != other_param:
 match = False
 
 return_type = method_info['return']
 other_return_type = other_method_info['return']
 if return_type != 'Object' and other_return_type == 'Object':
 erased = True
 elif return_type != other_return_type:
 match = False
 
 if match and erased:
 count += 1
 # print "FOUND! %s %s %s %s" % (class_name, method_name, params, return_type)
 # print " %s %s %s %s" % (class_name, method_name, other_params, other_return_type)
 
 print os.path.basename(sys.argv[1]) + '\t' + str(count) erased.py

Slide 97

Slide 97 text

$ column -t -s $'\t' \ <(echo -e "NAME\tERASED" \ && find apks -type f | \ xargs -L1 ./erased.py | \ sort -k2,2nr) Warning: This may take a while to run!

Slide 98

Slide 98 text

$ column -t -s $'\t' \ <(echo -e "NAME\tERASED" \ && find apks -type f | \ xargs -L1 ./erased.py | \ sort -k2,2nr) NAME ERASED com.amazon.mShop.android 4387 me.lyft.android 3269 com.amazon.avod.thirdpartyclient 2564 com.amazon.kindle 2439 com.imdb.mobile 2375 com.amazon.mShop.android.shopping 2259 com.nhl.gc1112.free 2178 com.Slack 2041 com.google.android.apps.giant 1971 com.ubercab 1877 com.squareup.cash 1819 com.twitter.android 1777 air.com.nbcuni.com.nbcsports.liveextra 1415 com.google.android.apps.docs.editors.slides 1378 com.audible.application 1206 com.robinhood.android 1196 com.foursquare.robin 1165 com.joelapenna.foursquared 1095 com.untappdllc.app 1091 com.google.android.apps.cloudconsole 1040 com.eventbrite.attendee 897

Slide 99

Slide 99 text

class Greeter {
 void sayHi() {
 System.out.println("Hi!");
 }1
 }2 
 
 
 
 class Example {
 public static void main(String... args) { Executor executor = Executors.newSingleThreadExecutor();
 Greeter greeter = new Greeter();
 }5
 }6

Slide 100

Slide 100 text

class Greeter {
 void sayHi() {
 System.out.println("Hi!");
 }1
 }2 class Example {
 public static void main(String... args) { Executor executor = Executors.newSingleThreadExecutor();
 final Greeter greeter = new Greeter();
 executor.execute(new Runnable() {
 @Override public void run() {
 greeter.sayHi();
 }4
 });
 }5
 }6

Slide 101

Slide 101 text

class Greeter {
 void sayHi() {
 System.out.println("Hi!");
 }1
 }2 class Example {
 public static void main(String... args) { Executor executor = Executors.newSingleThreadExecutor();
 Greeter greeter = new Greeter();
 executor.execute(() -> greeter.sayHi());
 }5
 }6

Slide 102

Slide 102 text

class Greeter {
 void sayHi() {
 System.out.println("Hi!");
 }1
 }2 class Example {
 public static void main(String... args) { Executor executor = Executors.newSingleThreadExecutor();
 Greeter greeter = new Greeter();
 executor.execute(greeter::sayHi);
 }5
 }6

Slide 103

Slide 103 text

$ javac *.java Retrolambda toolchain $ java -Dretrolambda.inputDir=. -Dretrolambda.classpath=. \
 -jar retrolambda.jar 
 $ dx --dex --output=example.dex *.class 
 $ dex-method-list example.dex

Slide 104

Slide 104 text

$ javac *.java Retrolambda toolchain $ java -jar android-sdk/build-tools/24.0.1/jack.jar \
 -cp android-sdk/platforms/android-24/android.jar \
 --output-dex . *.java Jack toolchain $ java -Dretrolambda.inputDir=. -Dretrolambda.classpath=. \
 -jar retrolambda.jar 
 $ dx --dex --output=example.dex *.class 
 $ dex-method-list example.dex 
 
 $ dex-method-list classes.dex

Slide 105

Slide 105 text

Code Retrolambda 2.1.0 Retrolambda 2.3.0 Jack 24.0.1

Slide 106

Slide 106 text

Code Retrolambda 2.1.0 Retrolambda 2.3.0 Jack 24.0.1 new Runnable() {
 @Override public void run() {
 greeter.sayHi();
 }
 } 2 2 2

Slide 107

Slide 107 text

Example () Example main(String[]) Example run(Runnable) Example$1 (Greeter) Example$1 run() Greeter () Greeter sayHi() java.io.PrintStream println(String) java.lang.Object () java.lang.Runnable run()

Slide 108

Slide 108 text

Example () Example main(String[]) Example run(Runnable) Example$1 (Greeter) Example$1 run() Greeter () Greeter sayHi() java.io.PrintStream println(String) java.lang.Object () java.lang.Runnable run()

Slide 109

Slide 109 text

Example$1 (Greeter) Example$1 run()

Slide 110

Slide 110 text

Example$1 (Greeter) Example$1 run() $ javap -c 'Example$1' final class Example$1 implements java.lang.Runnable { Example$1(Greeter); Code: public void run(); Code: 0: aload_0 1: getfield #1 // Field val$greeter:LGreeter; 4: invokevirtual #3 // Method Greeter.sayHi:()V 7: return }

Slide 111

Slide 111 text

Example$1 (Greeter) Example$1 run() $ javap -c 'Example$1' final class Example$1 implements java.lang.Runnable { Example$1(Greeter); Code: public void run(); Code: 0: aload_0 1: getfield #1 // Field val$greeter:LGreeter; 4: invokevirtual #3 // Method Greeter.sayHi:()V 7: return }

Slide 112

Slide 112 text

Code Retrolambda 2.1.0 Retrolambda 2.3.0 Jack 24.0.1 new Runnable() {
 @Override public void run() {
 greeter.sayHi();
 }
 } 2 2 2

Slide 113

Slide 113 text

Code Retrolambda 2.1.0 Retrolambda 2.3.0 Jack 24.0.1 new Runnable() {
 @Override public void run() {
 greeter.sayHi();
 }
 } 2 2 2 () -> greeter.sayHi() 6 or 7 4 3

Slide 114

Slide 114 text

Example () Example lambda$main$0(Greeter) Example main(String[]) Example run(Runnable) Example$$Lambda$1 (Greeter) Example$$Lambda$1 lambdaFactory$(Greeter) → Runnable Example$$Lambda$1 run() Greeter () Greeter sayHi() java.io.PrintStream println(String) java.lang.Object () java.lang.Runnable run() Retrolambda

Slide 115

Slide 115 text

Example () Example lambda$main$0(Greeter) Example main(String[]) Example run(Runnable) Example$$Lambda$1 (Greeter) Example$$Lambda$1 lambdaFactory$(Greeter) → Runnable Example$$Lambda$1 run() Greeter () Greeter sayHi() java.io.PrintStream println(String) java.lang.Object () java.lang.Runnable run() Retrolambda

Slide 116

Slide 116 text

Example lambda$main$0(Greeter) Example$$Lambda$1 (Greeter) Example$$Lambda$1 lambdaFactory$(Greeter) → Runnable Example$$Lambda$1 run() Retrolambda

Slide 117

Slide 117 text

Example lambda$main$0(Greeter) Example$$Lambda$1 (Greeter) Example$$Lambda$1 lambdaFactory$(Greeter) → Runnable Example$$Lambda$1 run() Retrolambda $ javap -c Example class Example { static void lambda$main$0(Greeter); Code: 0: aload_0 1: invokespecial #45 // Method sayHi:()V 4: return }

Slide 118

Slide 118 text

Retrolambda Example lambda$main$0(Greeter) Example$$Lambda$1 (Greeter) Example$$Lambda$1 lambdaFactory$(Greeter) → Runnable Example$$Lambda$1 run() $ javap -c Example class Example { static void lambda$main$0(Greeter); Code: 0: aload_0 1: invokespecial #45 // Method sayHi:()V 4: return }

Slide 119

Slide 119 text

Example lambda$main$0(Greeter) Example$$Lambda$1 (Greeter) Example$$Lambda$1 lambdaFactory$(Greeter) → Runnable Example$$Lambda$1 run() Retrolambda $ javap -c 'Example$$Lambda$1' final class Example$$Lambda$1 implements java.lang.Runnable { public void run(); Code: 0: aload_0 1: getfield #15 // Field arg$1:LGreeter; 4: invokestatic #21 // Method Example.lambda$main$0: 7: return }

Slide 120

Slide 120 text

Example lambda$main$0(Greeter) Example$$Lambda$1 (Greeter) Example$$Lambda$1 lambdaFactory$(Greeter) → Runnable Example$$Lambda$1 run() Retrolambda $ javap -c 'Example$$Lambda$1' final class Example$$Lambda$1 implements java.lang.Runnable { public void run(); Code: 0: aload_0 1: getfield #15 // Field arg$1:LGreeter; 4: invokestatic #21 // Method Example.lambda$main$0: 7: return }

Slide 121

Slide 121 text

Example lambda$main$0(Greeter) Example$$Lambda$1 (Greeter) Example$$Lambda$1 lambdaFactory$(Greeter) → Runnable Example$$Lambda$1 run() Retrolambda

Slide 122

Slide 122 text

Example -Example_lambda$1(Greeter) Example () Example main(String[]) Example run(Runnable) Example$-void_main_java_lang_String__args_LambdaImpl0 (Greeter) Example$-void_main_java_lang_String__args_LambdaImpl0 run() Greeter () Greeter sayHi() java.io.PrintStream println(String) java.lang.Object () java.lang.Runnable run() Jack

Slide 123

Slide 123 text

Example -Example_lambda$1(Greeter) Example () Example main(String[]) Example run(Runnable) Example$-void_main_java_lang_String__args_LambdaImpl0 (Greeter) Example$-void_main_java_lang_String__args_LambdaImpl0 run() Greeter () Greeter sayHi() java.io.PrintStream println(String) java.lang.Object () java.lang.Runnable run() Jack

Slide 124

Slide 124 text

Example -Example_lambda$1(Greeter) Example$-void_main_java_lang_String__args_LambdaImpl0 (Greeter) Example$-void_main_java_lang_String__args_LambdaImpl0 run() Jack

Slide 125

Slide 125 text

Code Retrolambda 2.1.0 Retrolambda 2.3.0 Jack 24.0.1 new Runnable() {
 @Override public void run() {
 greeter.sayHi();
 }
 } 2 2 2 () -> greeter.sayHi() 6 or 7 4 3

Slide 126

Slide 126 text

Code Retrolambda 2.1.0 Retrolambda 2.3.0 Jack 24.0.1 new Runnable() {
 @Override public void run() {
 greeter.sayHi();
 }
 } 2 2 2 () -> greeter.sayHi() 6 or 7 4 3 greeter::sayHi 4 3 or 4 3

Slide 127

Slide 127 text

lambdas.sh #!/bin/bash
 set -e
 
 ALL=$(dex-method-list $1)
 
 RL=$(echo "$ALL" | \grep ' lambda\$' | wc -l | xargs)
 JACK=$(echo "$ALL" | \grep '_lambda\$' | wc -l | xargs)
 
 NAME=$(basename $1)
 
 echo -e "$NAME\t$RL\t$JACK"

Slide 128

Slide 128 text

$ column -t -s $'\t' \ <(echo -e "NAME\tRETROLAMBDA\tJACK" \ && find apks -type f | \ xargs -L1 ./lambdas.sh | \ sort -k2,2nr) Warning: This may take a while to run!

Slide 129

Slide 129 text

$ column -t -s $'\t' \ <(echo -e "NAME\tRETROLAMBDA\tJACK" \ && find apks -type f | \ xargs -L1 ./lambdas.sh | \ sort -k2,2nr) NAME RETROLAMBDA JACK com.squareup.cash 826 0 com.robinhood.android 680 0 com.imdb.mobile 306 0 com.stackexchange.marvin 174 0 com.eventbrite.attendee 53 0 com.untappdllc.app 53 0

Slide 130

Slide 130 text

HashMap HashSet HashMap HashMap HashMap HashMap HashMap HashMap

Slide 131

Slide 131 text

HashMap HashSet HashMap HashMap HashMap HashMap HashMap HashMap ArrayMap ArraySet SparseArray SparseBooleanArray SparseIntArray SparseLongArray LongSparseArray

Slide 132

Slide 132 text

HashMap

Slide 133

Slide 133 text

HashMap int put(Integer, V)

Slide 134

Slide 134 text

HashMap int put(Integer, V) getKey() int

Slide 135

Slide 135 text

HashMap int Integer.valueOf put(Integer, V) getKey() int Integer.intValue

Slide 136

Slide 136 text

HashMap Node[] table; int size;

Slide 137

Slide 137 text

HashMap Node[] table; int size; ...

Slide 138

Slide 138 text

HashMap Node[] table; int size; ... Node int hash;
 K key;
 V value;
 Node next;

Slide 139

Slide 139 text

HashMap Node[] table; int size; ... Node int hash;
 K key;
 V value;
 Node next;

Slide 140

Slide 140 text

HashMap Node[] table; int size; ... Node int hash;
 K key;
 V value;
 Node next; Node int hash;
 K key;
 V value;
 Node next;

Slide 141

Slide 141 text

$ java -jar jol-cli-0.5-full.jar internals java.util.HashMap

Slide 142

Slide 142 text

$ java -jar jol-cli-0.5-full.jar internals java.util.HashMap # Running 64-bit HotSpot VM. # Objects are 8 bytes aligned. java.util.HashMap object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 4 4 (object header) 00 00 00 00 8 4 (object header) 9f 37 00 f8 12 4 Set AbstractMap.keySet null 16 4 Collection AbstractMap.values null 20 4 int HashMap.size 0 24 4 int HashMap.modCount 0 28 4 int HashMap.threshold 0 32 4 float HashMap.loadFactor 0.75 36 4 Node[] HashMap.table null 40 4 Set HashMap.entrySet null 44 4 (loss due to the next object alignment) Instance size: 48 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

Slide 143

Slide 143 text

$ java -jar jol-cli-0.5-full.jar internals java.util.HashMap # Running 64-bit HotSpot VM. # Objects are 8 bytes aligned. java.util.HashMap object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 4 4 (object header) 00 00 00 00 8 4 (object header) 9f 37 00 f8 12 4 Set AbstractMap.keySet null 16 4 Collection AbstractMap.values null 20 4 int HashMap.size 0 24 4 int HashMap.modCount 0 28 4 int HashMap.threshold 0 32 4 float HashMap.loadFactor 0.75 36 4 Node[] HashMap.table null 40 4 Set HashMap.entrySet null 44 4 (loss due to the next object alignment) Instance size: 48 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

Slide 144

Slide 144 text

$ java -jar jol-cli-0.5-full.jar internals 'java.util.HashMap$Node'

Slide 145

Slide 145 text

$ java -jar jol-cli-0.5-full.jar internals 'java.util.HashMap$Node' # Running 64-bit HotSpot VM. # Objects are 8 bytes aligned. java.util.HashMap$Node object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 int Node.hash N/A 16 4 Object Node.key N/A 20 4 Object Node.value N/A 24 4 Node Node.next N/A 28 4 (loss due to the next object alignment) Instance size: 32 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

Slide 146

Slide 146 text

$ java -jar jol-cli-0.5-full.jar internals 'java.util.HashMap$Node' # Running 64-bit HotSpot VM. # Objects are 8 bytes aligned. java.util.HashMap$Node object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 int Node.hash N/A 16 4 Object Node.key N/A 20 4 Object Node.value N/A 24 4 Node Node.next N/A 28 4 (loss due to the next object alignment) Instance size: 32 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

Slide 147

Slide 147 text

HashMap Node[] table; int size; Node int hash;
 K key;
 V value;
 Node next;

Slide 148

Slide 148 text

HashMap Node[] table; int size; Node int hash;
 K key;
 V value;
 Node next; 48 HashMap object

Slide 149

Slide 149 text

HashMap Node[] table; int size; Node int hash;
 K key;
 V value;
 Node next; 48 + 32 * entries HashMap object Node objects

Slide 150

Slide 150 text

HashMap Node[] table; int size; Node int hash;
 K key;
 V value;
 Node next; 48 + 32 * entries + 4 * (entries / loadFactor) + 8 HashMap object array of Node in HashMap Node objects

Slide 151

Slide 151 text

SparseArray int[] keys; V[] values; int size;

Slide 152

Slide 152 text

SparseArray int[] keys; V[] values; int size; ...

Slide 153

Slide 153 text

SparseArray int[] keys; V[] values; int size; ... ...

Slide 154

Slide 154 text

SparseArray int[] keys; V[] values; int size; ... ...

Slide 155

Slide 155 text

$ javac SparseArray.java $ java -cp .:jol-cli-0.5-full.jar org.openjdk.jol.Main \
 internals android.util.SparseArray

Slide 156

Slide 156 text

$ javac SparseArray.java $ java -cp .:jol-cli-0.5-full.jar org.openjdk.jol.Main \
 internals android.util.SparseArray # Running 64-bit HotSpot VM. # Objects are 8 bytes aligned. android.util.SparseArray object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 4 4 (object header) 00 00 00 00 8 4 (object header) 1a 69 01 f8 12 4 int SparseArray.mSize 0 16 1 boolean SparseArray.mGarbage false 17 3 (alignment/padding gap) N/A 20 4 int[] SparseArray.mKeys [0, 0, 0, 0, 0, 0, …] 24 4 Object[] SparseArray.mValues [null, null, null, …] 28 4 (loss due to the next object alignment) Instance size: 32 bytes Space losses: 3 bytes internal + 4 bytes external = 7 bytes total

Slide 157

Slide 157 text

$ javac SparseArray.java $ java -cp .:jol-cli-0.5-full.jar org.openjdk.jol.Main \
 internals android.util.SparseArray # Running 64-bit HotSpot VM. # Objects are 8 bytes aligned. android.util.SparseArray object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 01 00 00 00 4 4 (object header) 00 00 00 00 8 4 (object header) 1a 69 01 f8 12 4 int SparseArray.mSize 0 16 1 boolean SparseArray.mGarbage false 17 3 (alignment/padding gap) N/A 20 4 int[] SparseArray.mKeys [0, 0, 0, 0, 0, 0, …] 24 4 Object[] SparseArray.mValues [null, null, null, …] 28 4 (loss due to the next object alignment) Instance size: 32 bytes Space losses: 3 bytes internal + 4 bytes external = 7 bytes total

Slide 158

Slide 158 text

SparseArray int[] keys; V[] values; int size;

Slide 159

Slide 159 text

SparseArray int[] keys; V[] values; int size; 32 SparseArray object

Slide 160

Slide 160 text

SparseArray int[] keys; V[] values; int size; 32 + 4 * entries SparseArray object array of int keys

Slide 161

Slide 161 text

SparseArray int[] keys; V[] values; int size; 32 + 4 * entries + 4 * entries SparseArray object array of int keys array of V values

Slide 162

Slide 162 text

SparseArray int[] keys; V[] values; int size; 32 + (4 * entries + 4 * entries) / 0.75 SparseArray object array of int keys array of V values binary tree fudge factor

Slide 163

Slide 163 text

SparseArray 32 + (4 * entries + 4 * entries) / 0.75 HashMap 48 + 32 * entries + 4 * (entries / loadFactor) + 8

Slide 164

Slide 164 text

SparseArray 32 + (4 * entries + 4 * entries) / 0.75 HashMap 48 + 32 * entries + 4 * (entries / 0.75) + 8

Slide 165

Slide 165 text

SparseArray 32 + (4 * 50 + 4 * 50) / 0.75 HashMap 48 + 32 * 50 + 4 * (50 / 0.75) + 8

Slide 166

Slide 166 text

SparseArray 32 + (4 * 50 + 4 * 50) / 0.75 = 656 HashMap 48 + 32 * 50 + 4 * (50 / 0.75) + 8 = 1922

Slide 167

Slide 167 text

TODO (for you!) • Turn on "private member" inspection in the IDE and listen to it.

Slide 168

Slide 168 text

TODO (for you!) • Turn on "private member" inspection in the IDE and listen to it. • Report synthetic accessor methods in libraries as bugs.

Slide 169

Slide 169 text

TODO (for you!) • Turn on "private member" inspection in the IDE and listen to it. • Report synthetic accessor methods in libraries as bugs. • Update Retrolambda to 2.3.0 and try not to use it in open source libraries.

Slide 170

Slide 170 text

TODO (for you!) • Turn on "private member" inspection in the IDE and listen to it. • Report synthetic accessor methods in libraries as bugs. • Update Retrolambda to 2.3.0 and try not to use it in open source libraries. • Try using the Jack compiler in your app. Report failures to b.android.com.

Slide 171

Slide 171 text

TODO (for you!) • Turn on "private member" inspection in the IDE and listen to it. • Report synthetic accessor methods in libraries as bugs. • Update Retrolambda to 2.3.0 and try not to use it in open source libraries. • Try using the Jack compiler in your app. Report failures to b.android.com. • Use ProGuard without overly-matchy rules (-keep class com.foo.**).

Slide 172

Slide 172 text

Additional Presentations

Slide 173

Slide 173 text

http://jakes.link/eliminate-overhead

Slide 174

Slide 174 text

http://jakes.link/dex-ed

Slide 175

Slide 175 text

http://jakes.link/android-perf

Slide 176

Slide 176 text

Links • Jack generates extra method for method references
 http://b.android.com/218301 • Retrolambda generates extra method for lambdas / method references
 https://github.com/orfjackal/retrolambda/issues/81 • dex-method-list tool for showing methods in class/jar/aar/dex/apk
 https://github.com/JakeWharton/dex-method-list • Java Object Layout ("jol") tool for showing memory cost of types
 http://openjdk.java.net/projects/code-tools/jol/ • accessors.sh, erased.py, lambdas.sh helper scripts
 http://jakes.link/exploring-scripts

Slide 177

Slide 177 text

Jake Wharton Exploring Java Hidden Costs