Memory Leak of Dictionary used in singleton - ios

I have singleton. It contains a 2 dictionaries.
struct Stat {
var statHash:String
var displayDescription:String
var displayName:String
var displayIcon:String
var statIdentifier:String
}
class Singleton {
static let sharedInstance = Singleton()
var statsDesc = [String:Stat]()
var test = [String: String]()
init() {
test["a"] = "b"
}
}
let singlton = Singleton.sharedInstance
On using the leaks tool, I am getting a memory leak of the second dictionary(String, String).
Could someone please explain why this happens?
Link to the project on dropbox
Thanks for the help.

It was swift bug Memory Leak from Multiple Dictionary Properties

In effect, a singleton is a leak. Since the singleton holds a reference to itself, it is never released and neither are any of its properties.
The Leaks tool noted that singlton went out of scope, but the memory that was allocated was not released, so it flags a leak. In this case, however, a leak is exactly what you want.

Related

iOS + React Native - memory leaks

I'm considering making an iOS project in React Native. On iOS it's a big issue to find and fix so-called "retain cycles", i.e. when the two object store a strong reference to each other:
class Obj1 {
var delegate: Obj2?
}
class Obj2 {
var delegate: Obj1?
}
let obj1 = Obj1()
let obj2 = Obj2()
obj1.delegate = obj2
obj2.delegate = obj1
Does the React Native has a concept of a memory leak or retain cycle? Would the similar code in the JS counterpart create a retain cycle in React Native environment?
How about passing a closure capturing self? Would that also create a memory leak in React Native?
Summary:
Would the listed sample code (rewritten to JS) cause a memory leak in RN?
Would capturing self in a closure cause a memory leak?
You shouldn't really have two objects retaining strong references to each other, the delegate pattern is usually handled by having one strong and one weak reference, where the delegate is the weak one.
Now onto your questions:
Probably, but someone else might give you a better answer since I'm not entirely sure about RN.
Yes and no, depending on how you go about it.
If you use strong self, then definitely there will be a memory leak:
{ _ in
self.doSomething()
}
Better way is to use either weak self:
{ [weak self] _ in
guard let self = self else { return }
self.doSomething()
}
or unowned self if you can guarantee self is available in the closure at all times:
{ [unowned self] _ in
self.doSomething()
}

Why does wrapping a ReactiveSwift MutableProperty in a Property cause a leak?

Here's a Swift class that uses ReactiveSwift, wrapping a MutableProperty in a Property, and adding a subscription to that Property in a ScopedDisposable:
class Leaker {
let mutableProperty = MutableProperty<Int>(0)
var wrapperProperty: Property<Int> {
return Property(self.mutableProperty)
}
private var disposable: ScopedDisposable<AnyDisposable>?
init() {
let disposable = CompositeDisposable()
disposable += self.wrapperProperty.producer
.startWithValues { value in
print("\(value)")
}
self.disposable = ScopedDisposable(disposable)
}
}
If I give another class a property of type Leaker?, and then set it using self.leaker = Leaker(), this creates a leak. By "creates a leak," I mean it sets off the Leaks instrument, showing a leaked object labeled Malloc 32 Bytes, with a stack trace that includes Leaker.init() calling Leaker.wrapperProperty.getter.
Why does this leak? I'm finding it hard to understand exactly what is causing the memory allocated here to never be released.
Some other facts that might be useful:
This doesn't leak if I subscribe to mutableProperty directly
This doesn't leak if I wrap mutableProperty in a lazy property instead of a computed property
This doesn't leak if I create a temporary Leaker, e.g. let _ = Leaker()
I tried, but was not able to reproduce the memory leak. I've used your exact Leaker class with this code:
final class OtherClass {
let leaker: Leaker?
init() {
self.leaker = Leaker()
}
}
var otherClass: OtherClass? = OtherClass()
var mutablePropertyCompleted = false
otherClass!.leaker!.mutableProperty.producer.startWithCompleted {
mutablePropertyCompleted = true
}
var wrappedPropertyCompleted = false
otherClass!.leaker!.wrapperProperty.producer.startWithCompleted {
wrappedPropertyCompleted = true
}
otherClass = nil
if(!mutablePropertyCompleted) {
print("LEAK")
}
if(!wrappedPropertyCompleted) {
print("LEAK")
}
One thing to note is that MutableProperty sends completed in its deinit method, so it should be possible to detect a leak the way I did here.
But just to be sure I also profiled this with the memory leaks instrument which detected nothing.
Since you mentioned some specific circumstances in which this does not leak for you it might just be that the way I'm trying to reproduce the issue is wrong, maybe you can post a complete example?
Anyway, I don't see an error in the example you posted, so either this is a bug in ReactiveSwift, or its a false positive by the profiler (which has happened with ReactiveSwift before as jjoelson pointed out in his comment)

How NSMapTable works

I'm trying to figure out how NSMapTable works
So I'm trying in playground the following code:
class Person {
var name: String
init(name: String ) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
var hobyePerson : NSMapTable? = NSMapTable<Person, NSMutableString>
(keyOptions: .weakMemory, valueOptions: .weakMemory)
var rob : Person? = Person(name: "Rob Appleseed") // print : Rob Appleseed is being initialized
hobyePerson?.setObject("golf", forKey: rob)
hobyePerson?.count // return : 1
rob = nil // print : Rob Appleseed is being deinitialized
hobyePerson?.count // return : 1 (WHY ???!!!!)
as written in the documentation: "Keys and/or values are optionally held “weakly” such that entries are removed when one of the objects is reclaimed."
why even though I initialized the object so that it has a weak reference to the key-value pair when rob is deallocated, I still have an element in hobyePerson?
NSMapTable's weak behavior options work best when you don't care when keys/values are released, but rather, you do care that the keys/values aren't strongly retained and will be released at some point after the object of interest becomes nil.
Why so?
As a Foundation class, the authors of NSMapTable had to balance both features and performance.
Consequently, as an "optimization" for performance, they chose that weakly referenced objects that become nil are NOT immediately removed from the map table...! Rather, this happens "later" when it can be efficiently done -- such as when the map table internally gets resized, etc.
As #Luke also mentions in his answer, see this excellent writeup about an experiment done on NSMapTable's behavior for more details:
http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/
Yes, this is a strange and unfortunate behavior. This article goes into it in some depth. Although it doesn't explore weak-to-weak specifically, the behavior described is the same. As that author notes, hobyePerson.keyEnumerator().allObjects.count and hobyePerson.objectEnumerator().allObjects.count will contain 0 as expected at the end of all this. He also points out that Apple has sort of documented this behavior in the Mountain Lion release notes.
However, weak-to-strong NSMapTables are not currently recommended, as
the strong values for weak keys which get zero’d out do not get
cleared away (and released) until/unless the map table resizes itself.
Sorry I don't have a better explanation for you.
It didn't work for me so I implemented simple weak map like this.. Will improve it overtime but for now works:
import Foundation
private struct WeakValue<Value:AnyObject> {
weak var value: Value?
}
public class CSWeakValueDictionary<Key:AnyObject, Value:AnyObject> {
private let dictionary = NSMutableDictionary()
public subscript(source: Key) -> Value? {
get {
let value = (dictionary["\(source)"] as? WeakValue<Value>)?.value
if value == nil { dictionary.removeObject(forKey: "\(source)") }
return value
}
set { dictionary["\(source)"] = WeakValue(value: newValue) }
}
}

How do i release allocated memory for array?

I am not understanding how to give weak refrence to the array or release allocated memory of array, can anyone tell me how to fix this leak?
var menuDetails:[[String:Any]] = []//this my global array object
Getting following leak even i am using ARC.
Screenshot for array memory leak!
I was just scared about that memory leak,can anyone tell how do i fix it?
You don't want to use a weak reference. If you do that your array will get released immediately.
weak var weakArray: [[String:Any]]? = []
Will contain nil as soon as you create it.
Instead, you should set the array to nil (or empty) once you're done with the contents:
You could use `menuDetails.removeAll() to delete all the entries in the array, or you could change your declaration to make it an Optional
var menuDetails:[[String:Any]]? = []//this my global array object
And then set it to nil when you're done with it:
menuDetails = nil
An object will only be retained if another object has a strong reference to it. As soon as your view controller disappears, it will most likely be deallocated as well, which automatically removes its strong references to other objects. Thus, if imageArray is strongly referenced only by your disappearing view controller, the memory will automatically be released. You do not need to use an autoreleasepool.
In order to store weak references in arrays and/or dictionaries, you need an intermediate structure.
for example:
struct WeakRef
{
weak var object:AnyObject?
init( _ objectRef:AnyObject?)
{ object = objectRef }
}
// use WeakRef when you add object instances to your dictionary (or array)
menuDetails[0]["objectKey"] = WeakRef(yourObject)
// you will need additional code to get the actual object out of the intermediate structure
// and given that it is a weak reference you'll also need to deal with its optionality.
if let yourObject = (menuDetails[0]["objectKey"] as? WeakRef)?.object as? YourClass,
{
// ... do your thing with your object ...
}
The syntax could probably be made more legible by wrapping this in custom operators and generics but this is the general approach to it.

Swift 3 enums leak memory when the class contains an array

I found a memory leak in Swift. It gave me nightmares because my code was full of small leaks everywhere, and then I managed to reduce it to this small example,
import UIKit
enum LeakingEnum {
case
LeakCase,
AnotherLeakCase
}
class Primitive {
var lightingType: LeakingEnum = .LeakCase
var mysub : [Int] = []
init() {
mysub.append(80)
}
}
class ViewController: UIViewController {
var prim: Primitive?
override func viewDidLoad() {
super.viewDidLoad()
prim = Primitive()
}
}
If you run this program on an iPhone and Profile with Instruments, you'll find this leak in Array._copyToNewBuffer,
If I remove the call to mysub.append, it stops leaking. If I remove the enum from Primitive, it stops leaking as well. All the classes where I have an enum leak like this. What's going on with Swift enums?
Reproduced in Swift 3, Xcode 8.2.1, and iOS 10.2, on both an iPhone6 and an iPad Pro. Can't reproduce in the Simulator, or in a device with iOS 9.3.2.
You can download a minimal sample app here: https://github.com/endavid/SwiftLeaks
Is this a known bug? Is there any work around?
Edit:
Because this remind me of another enum bug, Accessor gives the wrong value in Swift 1.2/2.0 Release build only, I tried making the enum an #objc Int enum, but it still leaks. However, making lightingType directly an Int does fix the leak...
Edit2:
After updating my iPhone to 10.3 and Xcode to 8.3, the leak is gone. It seems it was an issue of iOS 10.2...
Hey #endavid managed to replicate the issue consistently. We spend a good time trying to figure out what was going on and your post helped a lot!
Here is the sample repo: https://github.com/Giphy/ios-memory-leak-sample
Radar: https://openradar.appspot.com/radar?id=4992108083544064
We are developing SDKs and same exact issue surfaced with a small difference. Since we wanted things to interop we added #objc to the enum definition and things started to leak exactly the way you described given your class has two properties, one enum and one mutable array.
Consistently reproduced the leak:
// Without #objc this enum won't leak
// however when this enum is included in a class
// which contains an array, it will leak
#objc enum leakingObjCMarkedEnum: Int {
// Just some random cases.
case apple, orange
}
// Wrapper class which contains an enum and Array
// The class needs to contain the the Array in order for
// the Enum to leak.
class WrapperClass {
// Optional enums marked with #objc will leak.
var leakyOptionalEnum: leakingObjCMarkedEnum?
// Include an array to trigger this behaviour.
// Empty arrays won't cause the leak, so lets add an arbitrary Int
var myArray: [Int] = [80]
}
class ViewController: UIViewController {
// Hang on to a reference to our Wrapper Class instance.
var wc: WrapperClass?
override func viewDidLoad() {
super.viewDidLoad()
// Allocate an instance of our class
// and things will start leaking at this point.
wc = WrapperClass()
}
}
Work Around:
If we convert the optional enum class property to a non-optional, leak will disappear.
// Let's convert the optional property to a non-optional
var leakyOptionalEnum: leakingObjCMarkedEnum = .orange
Edit:
It is fixed by guys # Apple:
https://bugs.swift.org/browse/SR-5625
PR: https://github.com/apple/swift/pull/11341

Resources