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

Identify and fix memory leaks in your app

Identify and fix memory leaks in your app

Talk given at Swiftable in Buenos Aires, Argentina in November 2019

Michel Bueno

November 28, 2019
Tweet

More Decks by Michel Bueno

Other Decks in Technology

Transcript

  1. ▸ Automatic Reference Counting (ARC) overview ▸ What is a

    leak? ▸ Reference types ▸ Main sources of leaks ▸ Identifying leaks ▸ Tools overview ▸ Xcode’s Memory Debugger ▸ Instruments ▸ Fixing leaks TOPICS COVERED IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP
  2. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP 2 references

    1 reference 0 reference object dead
  3. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP STRONG ▸

    Is the default reference type in Swift ▸ Protects the referred object from getting deallocated by ARC ▸ Increases the reference count by one ▸ Can be a let or var ▸ Can be optional or not
  4. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP STRONG A

    country strongImmutableReference A name An object in memory This object now has its reference count as 1
  5. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP STRONG Another

    country strongReference A name Another object in memory This object now has its reference count as 1
  6. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP STRONG Another

    country strongReference Two names Another object in memory This object now has its reference count as 2 strongOptionalReference
  7. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP WEAK ▸

    Doesn’t increase the reference count ▸ Doesn’t protect the referred object from being deallocated by ARC ▸ Is automatically set to nil on deallocation ▸ Must be a var ▸ Must be optional
  8. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP WEAK A

    string strongReference A name An object in memory This object now has its reference count as 1
  9. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP WEAK A

    string strongReference Two names An object in memory This object still has its reference count as 1 weakReference
  10. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP WEAK A

    string strongReference Two names Empty space in memory weakReference Object deallocated nil nil
  11. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP UNOWNED ▸

    Doesn’t increase the reference count ▸ Doesn’t protect the referred object from being deallocated by ARC ▸ Isn't automatically set to nil on deallocation ▸ Can be a let or var ▸ Cannot be an optional
  12. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP UNOWNED A

    country strongReference A name An object in memory This object now has its reference count as 1
  13. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP UNOWNED A

    country strongReference Two names An object in memory This object still has its reference count as 1 unownedImmutableReference
  14. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP UNOWNED A

    country strongReference Three names An object in memory This object still has its reference count as 1 unownedImmutableReference unownedReference
  15. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP UNOWNED A

    country Object deallocated Pointers to an empty slot in memory; They will cause an error when accessed Empty space in memory nil strongReference Three names unownedImmutableReference unownedReference
  16. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP REFERENCE TYPES

    RECAP Var Let Optional Non-Optional Strong ✓ ✓ ✓ ✓ Weak ✓ ✓ Unowned ✓ ✓ ✓
  17. USE A WEAK REFERENCE WHENEVER IT IS VALID FOR THAT

    REFERENCE TO BECOME NIL AT SOME POINT DURING ITS LIFETIME. CONVERSELY, USE AN UNOWNED REFERENCE WHEN YOU KNOW THAT THE REFERENCE WILL NEVER BE NIL ONCE IT HAS BEEN SET DURING INITIALISATION. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ AutomaticReferenceCounting.html IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP WEAK VS. UNOWNED - AN ADVICE FROM APPLE
  18. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP WHAT ARE

    LEAKS A leak is a portion of allocated memory that cannot be deallocated, and, by consequence, cannot be used again.
  19. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP WHY ARE

    LEAKS SO BAD ? ‣ Unwanted side effects: ‣ Memory warnings that can lead to: ‣ Slowness ‣ Screen freezes ‣ Eventual crashes ‣ All of that translated into bad App Store reviews/ratings.
  20. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP MAIN CAUSES

    OF LEAKS EVERY OTHER CAUSE IS A VARIATION OF THIS ({}) Retain cycles Closures Notification Center
  21. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP RETAIN CYCLES

    Retain cycles occur when two class instances hold strong references to each other.
  22. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP RETAIN CYCLES

    Object A Object B strong reference strong reference If A retains B and B retains A, then it's a leak
  23. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP Adapted from

    https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html
  24. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP Adapted from

    https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html Creates strong reference to a Country object Creates strong reference to a City object A City exists in and knows this Country
  25. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP CLOSURES A

    retain cycle can also occur if you have a closure in a class’ instance and the body of said closure uses that instance.
  26. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP Using self

    in a closure body creates a retain cycle to that class’ instance
  27. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP NOTIFICATION CENTER

    This is a variation of the closure’s case: the class’s instance is captured by the notification’s callback.
  28. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP Best practice

    says we must clear out observers on deinit()
  29. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP But deinit()

    won’t ever be called because the closure has a strong reference to this BASwiftable instance! Retains the class instance to the closure
  30. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP APPROACHES FOR

    IDENTIFYING LEAKS ▸ Running an inspection in your code ▸ Can be very tedious and time consuming ▸ Profile your app with Instruments: ▸ Leaks ▸ Allocations ▸ Debug you memory graph in Xcode Memory Debugger
  31. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP USING THE

    MEMORY GRAPH DEBUGGER ▸ Put your app in an initial state, such as your main screen, and take a memory snapshot Take memory snapshot In Xcode’s debugging toolbar
  32. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP USING THE

    MEMORY GRAPH DEBUGGER ▸ On the left panel, take a look at the classes that are in memory and how many instances they have (that is, how many objects of that class are allocated) by checking number in parenthesis. Eg: There is only one instance of the class ViewController
  33. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP USING THE

    MEMORY GRAPH DEBUGGER ▸ Run through a core flow/feature, repeat it several times and take a memory snapshot of your app again; ▸ On the left panel, observe three things: ▸ Is there any instance that should have been deallocated already? ▸ Has the number of instances increased? ▸ Has the amount of memory consumed increased? If any of these answers is yes, you have probably found a leak!
  34. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP DEMO APPLICATION

    - CHECKLISTS ▸ Click on add button in navigation bar to create an item ▸ Click on an item’s disclosure button to edit it ▸ Click on an item’s name to toggle its checked state ▸ Swipe left on an item to delete it
  35. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP WHAT WAS

    DONE ▸ Edited Item 1 ▸ Edited Item 2 ▸ Added Item 5 ▸ Viewed Item 3 ▸ Deleted Item 5 ▸ Edited Item 3 Open ItemDetailViewController
  36. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP Every time

    we opened the add/edit item screen, memory increased
  37. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP The memory

    occupied by instances of these classes was multiplied by 4 Persistent instances are never erased from memory; Transient instances are created and erased in the time frame we're analysing
  38. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP 5 times

    we opened the add/edit screen… 5 instances… We’ve started with 4 items and ended with 8
  39. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP FIXING LEAKS

    There are basically three ways of fixing leaks: ‣ Breaking retain cycles with weak ‣ Breaking retain cycles with unowned ‣ Using closure capture lists
  40. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP BREAKING RETAIN

    CYCLES ‣ Using unowned If A retains B and B retains A, then it's a leak Adapted from https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html Creates strong reference to a Country object Creates strong reference to a City object
  41. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP BREAKING RETAIN

    CYCLES ‣ Using unowned This breaks the retain cycle
  42. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP BREAKING RETAIN

    CYCLES ‣ Using weak Strong reference to self
  43. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP BREAKING RETAIN

    CYCLES ‣ Using weak This breaks the retain cycle Make protocol extend from class
  44. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP CLOSURE CAPTURE

    LIST A capture list is a Swift feature that allows you to define the rules to use when using one or more reference types within a closure’s body.
  45. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP CLOSURE CAPTURE

    LIST ‣ A pairing of the weak or unowned keywords with a reference to a class instance. ‣ Written within a pair of square braces, separated by commas. Place the capture list before a closure’s parameter list and return type if they are provided
  46. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP CLOSURE CAPTURE

    LIST Put them the very start of the closure, followed by the in keyword when it doesn't have a parameter list or return type
  47. IDENTIFY AND FIX MEMORY LEAKS IN YOUR APP RECAP ▸

    Memory leaks can be a little hard to find but easy to fix ▸ Retain cycles, Closures and NotificationCenter are the most common sources of leaks (but not the only ones) ▸ You can easily break retain cycles with weak and unowned ▸ Use swift's capture list for closures ▸ Instruments and Xcode Memory Debugger are great tools to find leaks ▸ Always profile your app and keep an eye on memory consumption