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

Application performance: an everyday struggle

Application performance: an everyday struggle

Talk about some hot topics and best practices regarding application performance in areas such as networking, threading and ui design.

Presented at GDG Android Athens

Nasos Loukas

June 07, 2017
Tweet

More Decks by Nasos Loukas

Other Decks in Programming

Transcript

  1. Definition of performance • Keeping 60fps • It has to

    do with the… brain… • Eye is streaming visual signals, stop motion is a hack • 12fps… and we have motion • 24fps… cheap fluidity • 60fps… the sweet spot • Managing Memory • Preserving Battery • Saving Data
  2. Definition of performance (Developer) Soooo…What does 60fps really mean? •

    1s = 1000ms • 1000ms / 60frames = 16,66666ms/frame • 16ms to do what? • Load/Calculate/Draw… Everything!
  3. Definition of performance (Developer) What happens if I lose this

    window? • The next frame is dropped • Fall below 60fps • laggy / janky experience • User uninstalls the app • Whole world collapses…
  4. • CPU • GPU • Memory • Battery Gather HeapViewer

    Traceview Insight FIX but don’t rush! Action Performance Lifecycle My app has issues? What can I do?? • Most developers don’t think about performance until it has already become a problem!
  5. Many… many tools • LINT • Android Monitor • On-device

    • Hierarchy Viewer • HeapViewer • Traceview • AllocationTracker • Systrace • New Profiler!!
  6. Best practices Sum up best practices for • Networking •

    Threading • UI(-ing) • Coding (for Android)
  7. Best practices… Networking • Reduce the amount of time between

    when the user wants data and the network returns it • Single biggest battery drain! • More data transferred => bigger cost for the user (metered networks) • Things you can’t control • Bandwidth • Latency • Cellular connection speed • Things you can control/optimize • Radio active time • Number of requests • Data per request (at least try…)
  8. Best practices… Networking (radio active time) • Stuff user asks

    to do • Just do it • Stuff server needs to update • FCM, data update notification • Stuff needs to be updated frequently • AlarmManager • SyncAdapter • JobScheduler (21+) • GcmNetworkManager (PlayServices 7.5)
  9. Best practices… Networking (adapting to latency) • Repeated task as

    fast as possible… every sec! • Bottleneck!! • Multiple pending requests • Multiple useless UI updates • Mmmm ok… why not check network first? • Best case interval • Adaptive intervals • No repeated scheduling • Evaluate response times
  10. Best practices… Networking (prefetching) • Predict what data we are

    going to need and fetch • E.g. user settings, common app data • What does this have to do with networking performance? • Each radio request has overhead • Load data when executing another mandatory request • E.g. after login load account related data • Tricky balancing problem
  11. Best practices… Networking (data reduction) • The more data sent

    • The more battery consumed • The more cost for the user • JSON and XML (XML? Really??) • Human readable formats -> bloated • Minification • E.g. rates 43 entries • XML = ~7KB • JSON= ~6KB • Minified JSON = ~2KB • Protocol buffers • FlatBuffers
  12. Best practices… Networking (caching) Reading data from memory/device will always

    be faster than network • HttpResponseCache • Cache-Control header • Server-side controlled • (Disk)LruCache • Least Recently Used Cache • On cache full, delete LRU entry • Libraries to the rescue… • Volley • OkHttp • Retrofit • Picasso • Glide
  13. Best practices… Threading • On application launch the system creates

    a new single threaded process -> Main/UI thread! • 16ms for main thread to respond to • UI Drawing • System Events • Input Events • Application • Service • Alarm • Offload as much work as possible! {Our Code}
  14. Best practices… Threading (the Android way) • AsyncTask • All

    tasks run in a dedicated thread • HandlerThread • Long running thread that grabs work from a queue and operates on it • Thread pool (Executor) • Handles all heavy lifting of parallel processing • IntentService • Kind of hybrid between Service and HandlerThread • The Service misconception • Not a background task • Creating/Scheduling/Running/Destroying services cost time and memory • Without proper handling a service could live forever
  15. Best practices… Threading (priority) • Priority is assigned based on

    the lifecycle • Foreground group • Background group • New threads take the same priority as the spawning thread • THREAD_PRIORITY_DEFAULT • Waste CPU time • Explicit priority • Process.setThreadPriority() • AsyncTask and IntentService do that by default
  16. Best practices… Threading (main thread) • Moving back to main

    thread • Activities (and views) can be destroyed at any time • Memory leaks (in a bit) • Work for nothing • Decouple background tasks from UI as much as possible • A good place to cache
  17. Best practices… Threading (Retrofit) • Always evaluate the libraries you

    are using • Retrofit for convenience return callbacks in main thread • But I have more work that needs to be done • Return to main manually • How to check my thread?
  18. Best practices… UI (leaks) • Leak is an object that

    no longer needed but has reference that don't allow it to be garbage collected • Chain leaks • Fill memory heap • Cause more GC events • Consume precious CPU time • Drop frames
  19. Best practices… UI (common leaks) • Static view references •

    View references in collections • Dynamic layout • Views should always have weak references • WeakHashMap<Integer,ChartView> • Objects are strong referenced • LeakHashMap • How to identify? • Memory Monitor • LeakCanary
  20. Best practices… UI (layout taxation) • Design your layouts wisely

    • Know the impact of every element • Avoid nested weights • View measured twice • Avoid nested layouts • Avoid overdraw • Be careful with RelativeLayout • 2 layout passes to draw by definition • How to locate/fix? • Avoid layout requests • HierarchyViewer • Systrace (measure/layout times) RelativeLayout EditText ListView GridView ImageView TextView GridView ImageView TextView GridView ImageView TextView 2x 2x 4x 8x
  21. Best practices… UI (custom views) • Android has over 70

    widgets • Not enough in many cases • Create a custom view with caution • Be aware of your onDraw • Avoid allocations • Avoid long running code • Only draw what is necessary • Avoid unnecessary invalidations
  22. Best practices… UI (approximation) • Cutting corners • Not always

    a bad thing • Decide where carefully • View with real time updates • Small lags when scrolling • User review that app has lags  • Disable invalidation when scrolling • User changes review… the app now is blazing fast  • Same with images • Load smaller resolution if only meant for thumbnails
  23. Best practices… Coding • Don’t do work that you don’t

    need to • Don’t allocate memory if you can avoid • Avoid creating unnecessary objects • Prefer static methods • 15-20% faster • Use static final for constants • Know your platform • Prefer API methods than doing by yourself • Proposed for Java doesn’t mean it work best on Android
  24. Best practices… Coding (collections) • HashMap<K,V> • Memory inefficient •

    Extra logic for chaining etc • ArrayMap<K,V> instead • Better memory use • Slower addition/deletion/retrieval • Faster iteration • When to use? • <1000 items and lots of accesses infrequent insertions/deletions • Maps of maps with many iterations
  25. Best practices… Coding (collections - autoboxing/unboxing) • Primitives can’t be

    used by generic collections at runtime • Autoboxing converts from primitives to their respective objects • Unboxing to retrieve the underlying primitive • HashMap<Integer, V> accessed via int • Autoboxing on every action • New allocation • Unboxing logic • 16bytes for Integer rather than 4 for int • SparseArray<V> instead • Pros/cons of ArrayMap • No autoboxing/unboxing
  26. Best practices… Coding (collections - iterations) • Every Iterator comes

    with memory allocation • One not a big deal but within other iterations?? • next() function adds additional logic • Android platform team is supposed to have a policy to avoid Iterators • Lets test this… • Nexus 5 • Android 6.0.1 • 500K random integers in ArrayList • Avg of 10 time run Iteration Time (ms) while (it.hasNext()) 530 for (int i = 0; i < integers.size(); i++) 533 for (int i = 0; i < size; i++) 296 for (Integer i : integers) 529
  27. Best practices… Coding (enums) • A little background • When

    the app loads, Android will allocate a dedicated memory space • All DEX code is loaded into this • The bigger the DEX, the lowest the memory for the runtime allocations • Why Enums are such an issue? • Enums bloat DEX files end eat up heap space • E.g. 3 states • With static final int: +124bytes • With Enum: +1632bytes (13x more) • Additional runtime overhead • @IntDef and @StringDef
  28. Conclusions It’s not the big glaring topics that cause the

    most problems but the little things that when added together create huge headaches Tools not rules In the end what’s important is to understand the trade-offs and know the difference to make informed decisions
  29. References • Best Practices for Performance https://developer.android.com/training/best-performance.html • Android Performance

    Patterns https://www.youtube.com/playlist?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE • Evaluating Performance https://source.android.com/devices/tech/debug/eval_perf • Threading Performance https://developer.android.com/topic/performance/threads.html