6

My Swift globals are not getting deinitialized.

class Person {
  let name: String
  init(name: String) {
    self.name = name
    println("\(name) is being initialized")
  }
  deinit {
    println("\(name) is being deinitialized")
  }
}

func local() {
  let person = Person(name: "Local")
}

local()

var personp: Person? = Person(name: "Optional Global")
personp = nil

var person = Person(name: "Global")

I am running this in a standalone binary (because apparently the playground has issues with deinit) with optimizations disabled, using Xcode6-Beta3:

> xcrun swift -O0 arc.swift && ./arc
Local is being initialized
Local is being deinitialized
Optional Global is being initialized
Optional Global is being deinitialized
Global is being initialized

Note the missing Global is being deinitialized.

I can't even figure out if this is expected behaviour or a bug, so if it is the former then references to the relevant legalese will be appreciated.

Community
  • 1
  • 1
Manav
  • 10,094
  • 6
  • 44
  • 51
  • Why would global be reinit? It's a property effectively isn't it? – Woodstock Jul 12 '14 at 07:52
  • Both the current answers mention that this is not entirely unexpected given the underlying implementation. As I stated in the question, if this is the case, then I was hoping for a more definitive citation. The reason why this is an issue is that the global could be tracking some sort of resource (file, database connection etc), and given the current behaviour, the onus would be on the programmer to ensure that no such "resource owners" are kept as global. – Manav Jul 14 '14 at 11:04

2 Answers2

5

it looks fine to me... on ending the app nothing is deallocated - there is no point


deinit is only meant to FREE memory and remove observers and stuff - upon ending the process though, this is kinda 'useless' as the process memory 'will be wiped' anyways

==>

SO:

never put anything but memory management / observer related stuff in deinit

If you need a dedicated stop method - write one and call it explicitly before quitting the process

Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • I agree - it _seems_ that we should not be keeping any "resource owners" as global objects if we're relying on their deinit being called. I was kind of hoping for a citation though :), because this is not necessarily the case in all languages. For example, C++ (seemingly one of the influences on Swift) does call destructors for global objects. – Manav Jul 14 '14 at 11:09
4

Think of the last line of code as:

var personp: Person? = Person(name: "Optional Global")
personp = nil

var person = Person(name: "Global")

exit(0)

Since person is never set to another value, ARC never decreases the retain count before the exit.

Swift works like a C program in that execution simply terminates and then all memory allocated to the process is returned in one sweep.

This is very different from in-execution memory handling which relies on in-process events to free memory. Since all execution of the program has completely stopped, there is no thread to run the deinit.

So in conclusion, this is just as it should be.

Nuoji
  • 3,438
  • 2
  • 21
  • 35
  • Since Swift is supposed to be extra safe to work with, one could reasonably expect it to run deinitializers before (regular) termination. (Of course, if you `kill -9` nothing can be done.) – Raphael Jan 19 '17 at 15:22