Incorrect iOS 8 memory management

I noticed that iOS 8 memory management is not working as I might expect. This can be found in a simple application with one view. If you download, for example, 100 views first, the system will allocate memory for them. As a result, the amount of used memory will be increased (for example, up to 17.1 MB). Then, for some reason, you decided to delete those views and reclaim your memory. If your application took up 15 MB of memory when it was first loaded, then obviously you want your application to occupy the same amount of memory as it was originally running (i.e. 15 MB). But after removing and deinitializing all added views, you won't get 15 MB, but something close to it (it could be 15.2 or 15.3 MB). If you continue to add and remove views sequentially,the amount of memory used will increase every time (not much).

If you want to play with him:

1) Create a single project.

2) Add subclasses of the custom view class that you create and delete.

var deinited = 0

class TestView: UIView {
    let label: UILabel

    init(text: String, frame: CGRect) {
        label = UILabel(frame: CGRectMake(0, 0, frame.width, frame.height))
        label.text = text
        super.init(frame: frame)
        addSubview(label)
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    deinit {
        println("\(deinited++)")
    }
}

      

Deinitialization will be broadcast.

3) Then go to ViewController .

class ViewController: UIViewController {
    var views = [TestView]()

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func load(sender: AnyObject) {
        let rect = CGRectMake(0, 0, 100, 60)
        for i in 0...99 {
            let testView = TestView(text: "\(i)", frame: rect)
            testView.hidden = true
            views.append(testView)
            view.addSubview(testView)
        }
    }

    @IBAction func unload(sender: AnyObject) {
        for testView in views {
            testView.removeFromSuperview()
        }

        views.removeAll(keepCapacity: false)
    }
}

      

I added 2 buttons and created actions for them to load and unload views.

Run the project load and unload the Debug Navigator check several times .

Deinitialization is going fine, but some of the memory is not returned. If you have a large project that downloads and then unloads views many times, it becomes a problem.

My guess was that the system might have some sort of cache system. Therefore, some objects are still in memory for future use. But that doesn't sound like Apple.

Please let me know if you know anything about this issue.

+3


source to share


1 answer


I see a leak between 580KB over 100 views. Most of these seem to be different things inside CoreAnimation, although there is a lot of caching in it, so it is not entirely clear how many "leaks" are going on versus "proactive caching", which amortizes many uses. Over 20 iterations, I see about 150K total memory growth.

The short answer is yes, don't add or remove hundreds of views. There are two good answers: first, you should generally reuse views if you are going to add and remove them like that (or just hide them). If you really need to create and destroy them all the time, consider using CALayers rather than full views. Hundreds of subqueries are usually not a great approach unless you need to interact with them (which is what views give you layers).



Another short answer: open the radar (bugreport.apple.com). The growth is probably a bit taller than it should be and feels like this is more than just caching. When you say "there might be some kind of cache system" and then "but it doesn't sound like Apple", it's not clear what you mean. Apple caches all the time. This is actually incredibly common in UIKit.

But yes, UIKit has leaks. He always had leaks. Open up radars and avoid things that make them worse (like adding and removing hundreds of views).

+2


source







All Articles