36
Managing Memory in Swift (Yes, that's a thing) Swift Cloud Workshop 2 Austin, TX 30 September 2017 Illustration Renders by https://pixabay.com/en/users/3dman_eu-1553824/ @CarlBrwn

Managing Memory in Swift (Yes, that's a thing)

Embed Size (px)

Citation preview

Page 1: Managing Memory in Swift (Yes, that's a thing)

Managing Memory in Swift (Yes, that's a thing)

Swift Cloud Workshop 2 Austin, TX30 September 2017

Illustration Renders

by https://pixabay.com/en/users/3dman_eu-1553824/

@CarlBrwn

Page 2: Managing Memory in Swift (Yes, that's a thing)

Managing Memory in Swift (Yes, that's a thing)

Swift Cloud Workshop 2 Austin, TX30 September 2017

Illustration Renders

by https://pixabay.com/en/users/3dman_eu-1553824/

@CarlBrwn

Page 3: Managing Memory in Swift (Yes, that's a thing)

Obligatory Bio• Swift on the Server Developer at IBM

• First iOS App in 2008, many projects since

• Author, App Accomplished

• Meetup Organizer

• SwiftAustin & CocoaCoders

• Parent

@CarlBrwn

Page 4: Managing Memory in Swift (Yes, that's a thing)

Is Swift on the Server READY?

• In my (personal) Opinion, [NOT speaking on behalf of IBM], this answer depends on two things:

1. Do you need the ecosystem to have more features that you can build yourself?

in the Cloud[For your app?]

@CarlBrwn

Page 5: Managing Memory in Swift (Yes, that's a thing)

Tale of Two Ecosystems• NPM Claims 475,000 available node.js

packages.

• IBM’s Swift Package Catalog has 4000 entries (last I looked), and that number includes at least some iOS-only packages.

• So if you want to do Server-Side Swift, be prepared to roll your own.

• Personally, I’m okay with writing my own left-pad, but YMMV.

@CarlBrwn

Page 6: Managing Memory in Swift (Yes, that's a thing)

Is Swift on the Server READY?

• In my (personal) Opinion, [NOT speaking on behalf of IBM], this answer depends on two things:

1. Do you need the ecosystem to have more features that you can build yourself?

2. Can you manage your own memory?

in the Cloud[For your app?]

@CarlBrwn

Page 7: Managing Memory in Swift (Yes, that's a thing)

Previously on “Conferences

with Carl”:

try!Swift NYC 2017• This talk expands on that talk• It should be up on video at

Realm sometime soon• Not necessary to have seen it

@CarlBrwn

Page 8: Managing Memory in Swift (Yes, that's a thing)

0

35

70

105

140

PR Fixes

CodeOrdering Counting Encapsulation Logic(App) MemoryNaming Optionals Performance Threading TypingUnclear

PRs Meeting Criteria (502 total)

?

Today’s Talk

@CarlBrwn

Page 9: Managing Memory in Swift (Yes, that's a thing)

Memory (6.4%)• Most people I talk to don’t think of Swift

Memory Management as a problem

• Some of the Apple folks I talked to about it at WWDC this year were surprised, too (at first)

• It is a real problem, and it’s serious

• And it’s worse on Linux…

• For 3 primary reasons:

@CarlBrwn

Page 10: Managing Memory in Swift (Yes, that's a thing)

Reason 1: Duration

• Cloud apps run longer (in general)

• Cloud apps can’t restart themselves in the background while you’re checking Facebook

• Memory leaks are cumulative

• Cloud costs scale with dedicated RAM

@CarlBrwn

Page 11: Managing Memory in Swift (Yes, that's a thing)

Reason 2: Tools

• We don’t have Xcode

• We don’t have Instruments

• We don’t have cycle detectors

• In fact, we don’t have any Swift-aware memory diagnostics on Linux at all

@CarlBrwn

Page 12: Managing Memory in Swift (Yes, that's a thing)

Reason 3: Structure• iOS (and Mac) Apps have a Structure:

• Application Delegate

• View Controllers

• Views

• Well-tested clean-up code

• (e.g. Views reclaimed when removed from the screen)

• By contrast, Linux has: main

• Biggest problem w/Swift on Linux (IMNSHO)@CarlBrwn

Page 13: Managing Memory in Swift (Yes, that's a thing)

BRIEF Intro to ARC• Automatic Reference Counting

• In the Old Days (2009), we would call retain, release or autorelease on each object by hand

• Apple published rules about when you were supposed to use each

• Apple wrote an Analyzer tool that would tell you when you broke the rules

• ARC does for you what those rules said to do

1/6

@CarlBrwn

Page 14: Managing Memory in Swift (Yes, that's a thing)

BRIEF Intro to ARC• Each object has a counter

• (Originally this was part of the NSObject implementation, but now it applies to more things, but I’m probably still going to say “object” today)

• When you take a reference to something (like putting it in an ivar), you increment its counter

• When you’re done with it (or the system is done with you), its counter is decremented

• The object only knows its count. It has no idea who is pointing at it.

2/6

@CarlBrwn

Page 15: Managing Memory in Swift (Yes, that's a thing)

BRIEF Intro to ARC• ARC keeps things around as long as their

reference counts are greater than zero

• When a counter drops to zero, the object is available to be reclaimed

• Reclamation happens periodically and deterministically, but not necessarily instantly

3/6

@CarlBrwn

Page 16: Managing Memory in Swift (Yes, that's a thing)

BRIEF Intro to ARC• When an object is reclaimed, all the things

it’s referencing have their counts reduced by one

• That often causes those things to get reclaimed in turn, and so on

• Unlike GC, no marking or sweeping is needed during reclamation

• The system doesn’t need to pause the whole system to free up memory

RAMARC

Object

4/6

@CarlBrwn

Page 17: Managing Memory in Swift (Yes, that's a thing)

ARC-Optimized ArchitectureThis is the world ARC wants (and expects)

5/6

BRIEF Intro to ARC

@CarlBrwn

Page 18: Managing Memory in Swift (Yes, that's a thing)

BRIEF Intro to ARC• When two things refer to each other, ARC is

powerless

• Neither count will ever be set to zero

• The objects can never be reclaimed

• Some Garbage Collectors in Other Languages can find and reclaim these kinds of cycles at runtime (with a performance penalty), but in Swift it’s not happening

• If no other objects can reach either of these, you get a classic leak

6/6

@CarlBrwn

Page 19: Managing Memory in Swift (Yes, that's a thing)

Good Structures• Clear lines of ownership

• Clear relationships & hierarchies

• Tend to use ivars/properties

• Tend not to remember things passed in from outside (especially from caller)

• Tend to reinforce existing relationships & events

• e.g. Memory gets naturally reclaimed when views leave the screen or network connections drop

@CarlBrwn

Page 20: Managing Memory in Swift (Yes, that's a thing)

Bad Structures• Tangled or unclear relationships

• Strong references to things passed in from outside

• Things captured in closures

• Hierarchies not rooted in natural events

• e.g. Needs clean up functions instead of it “just happening”

• “Missed Dominos”

@CarlBrwn

Page 21: Managing Memory in Swift (Yes, that's a thing)

You have to Measure• This is a necessary step - you can’t reliably quantify

memory issues from reading code (if you can, you should be mining bitcoin in your head)

• This has to happen at runtime, static analysis won’t help

• You need either a production-like synthetic load, or to measure in actual production (or both)

• Honestly, I don’t think many people do this (even for iOS)

@CarlBrwn

Page 22: Managing Memory in Swift (Yes, that's a thing)

My Measuring Scripts are Availablehttps://github.com/carlbrown/SwiftServerComparison

May or may not work for your use-case, but you’re welcome to them@CarlBrwn

Page 23: Managing Memory in Swift (Yes, that's a thing)

Wish there was a better wayRun long test, grab `ps` logs,

graphRollback, Next or Fixed?

Test with `heaptrack` to find next

Area of interest

Change code

@CarlBrwn

Page 24: Managing Memory in Swift (Yes, that's a thing)

Graph of RSS from `ps aux`Moving the slope, One little fix at a time

@CarlBrwn

Page 25: Managing Memory in Swift (Yes, that's a thing)

Variability can be a ProblemHard to see the leak (signal) when leak is small compared to the spread (noise)

This was happening because of clean-up functionsAs you run the test longer, it becomes less of an issue@CarlBrwn

Page 26: Managing Memory in Swift (Yes, that's a thing)

DurationThis is a half hour run

@CarlBrwn

Page 27: Managing Memory in Swift (Yes, that's a thing)

Duration (cont)Same run, full duration (~5 hours)

@CarlBrwn

Page 28: Managing Memory in Swift (Yes, that's a thing)

Wish there was a better wayRun long test, grab `ps` logs,

graphRollback, Next or Fixed?

Test with `heaptrack` to find next

Area of interest @CarlBrwn

Page 29: Managing Memory in Swift (Yes, that's a thing)

Darwin’s cool tools aren’t for you…Nothing remotely like it on Linux

Even if you test on Darwin, there may still be Linux leaks@CarlBrwn

Page 30: Managing Memory in Swift (Yes, that's a thing)

…And that’s a real shameBecause the leaks that happen when you don’t have an

App Delegate structure can get REALLY convoluted@CarlBrwn

Page 31: Managing Memory in Swift (Yes, that's a thing)

Use heaptrack & heaptrack_guiNot constrained to single thread like valgrind

But no awareness of Swift reference counts or structure@CarlBrwn

Page 32: Managing Memory in Swift (Yes, that's a thing)

Wish there was a better wayRun long test, grab `ps` logs,

graphRollback, Next or Fixed?

Test with `heaptrack` to find next

Area of interest

Change code

@CarlBrwn

Page 33: Managing Memory in Swift (Yes, that's a thing)

So what code do you change?• heaptrack only gives us the line of code that allocated the object

that is “stuck" in memory (& you may want to run swift-demangle)

• Find all the places that object is used and especially all the times it’s passed to a closure or as an argument

• See if you can make them weak without crashing (or unowned, but only if you have to - it’s not safe)

• See if making it weak at that point changes the slope of the graph

• Make only one change at a time, and measure

• Continue until you’ve found the right place(s) to make weak

• NOTE: This will only work if ownership is clear. If not, refactor

Good Question

@CarlBrwn

Page 34: Managing Memory in Swift (Yes, that's a thing)

Most of my changes turn out to be dead-endsThe ones that make the slope better get merged to `master`

@CarlBrwn

Page 35: Managing Memory in Swift (Yes, that's a thing)

Thank You& Good Luck

@CarlBrwn

Page 36: Managing Memory in Swift (Yes, that's a thing)

Thank You& Good Luck

@CarlBrwn