17.2 强引用循环

当两个对象的存储属性互相引用对方的时候,一个对象释放的前提是对方先释放,另一对象释放的前提也是对方先释放,这样就会导致类似于“死锁”的状态,最后谁都不能释放,导致内存泄漏。这种现象就是强引用循环

假设我们开发一个人力资源管理系统,其中Employee(员工)与Department(部门)的关联关系如图17-3所示,Employeedept属性关联到DepartmentDepartmentmanager(部门领导)属性关联到Employee

{%}

图 17-3 EmployeeDepartment的关联关系

示例代码如下:

  1. class Employee {
  2. var no : Int
  3. var name : String
  4. var job : String
  5. var salary : Double
  6. var dept : Department?
  7. init(no : Int, name: String, job : String, salary : Double) {
  8. self.no = no
  9. self.name = name
  10. self.job = job
  11. self.salary = salary
  12. println("员工\(name) 已经构造成功。")
  13. }
  14. deinit {
  15. println("员工\(name) 已经析构成功。")
  16. }
  17. }
  18. class Department {
  19. var no : Int = 0
  20. var name : String = ""
  21. var manager : Employee?
  22. init(no : Int, name: String) {
  23. self.no = no
  24. self.name = name
  25. println("部门\(name) 已经构造成功。")
  26. }
  27. deinit {
  28. println("部门\(name) 已经析构成功。")
  29. }
  30. }
  31. var emp: Employee?
  32. var dept: Department?
  33. emp = Employee(no: 7698, name: "Blake", job :"Salesman", salary : 1600)
  34. dept = Department(no : 30, name: "Sales")
  35. emp!.dept = dept
  36. dept!.manager = emp
  37. emp = nil
  38. dept = nil

上述代码第①行定义了员工类Employee,第②行代码var dept : Department?声明所在部门的属性,它的类型是Department可选类型。第③行代码定义了部门类Department,第④行代码 var manager : Employee?声明部门领导的属性,它的类型是Employee可选类型。

第⑤行代码var emp: Employee?声明Employee引用类型变量emp,第⑥行代码var dept: Department?声明Department引用类型变量dept

第⑦行代码创建Employee对象并赋值给empempEmployee对象建立强引用关系。第⑧行代码创建Department对象并赋值给deptdeptDepartment对象建立强引用关系。但是此时,empdept两个对象之间并没有建立关系,它们之间的关系如图17-4所示。

{%}

图 17-4 empdept对象之间没有建立关系

代码第⑨行emp!.dept = dept将引用变量dept赋值给Employeedept属性,代码第⑩行dept!.manager = emp将引用变量emp赋值给Departmentmanager属性,此时empdept两个对象就建立了关系。它们之间的关系如图17-5所示。

{%}

图 17-5 empdept对象之间建立关系

如果我们通过第⑪行代码emp = nil和第⑫行代码dept = nil断开引用关系,如图17-6所示,但是Employee对象和Department对象并没有被释放。这是因为①号引用关系(Employee对象dept属性引用Department对象) 保持Department对象不被释放。而②号引用关系(Department对象manager属性引用Employee对象)保持Employee对象不被释放。

{%}

图 17-6 empdept强引用断开

最后Employee对象和Department对象都没有被释放,这就是强引用循环,会导致内存泄漏。