I turned on garbage collection (objective-c 2.0) and the image for the status item disappeared when I restarted my application. I am manually memory managing the image and status item.
This application works normal when garbage collection is off (i.e. the status item doesn't disappear.) Is there a way to make the garbage collection not collect specific variables or should I turn it off completely? When turning on garbage collection, my app's memory drops from 100mb to 2mb.
How are you "manually managing the memory of the image and status item"? If you are using release and retain, they are actually ignored under GC.
Under GC, objects stick around if (a) you have a strong reference to them in GC scanned memory or you (b) CFRetain them.
Just keep a reference to it as an instance variable of some object e.g. the controller of the view it appears in.
Related
I just started creating an app using SceneKit and SpriteKit and ARC for the first time. I noticed that the memory usage is quickly increasing when I switch between different Views. My first thought was that I have memory leaks but I am not sure now. The behavior even occurs in this basic example:
for(int r=0;r<9999999;r+=1){
NSString *s=[NSString stringWithFormat:#"test%i",r];
s=nil;
}
From my understanding an NSString Object is created and directly released in this loop. I've tried this example in the iPhone-Simulator and on an iPhone and it makes the app use several hundreds MB of RAM after this loop is executed. (I am checking the memory usage with the Xcode debug navigator)
I am obviously misunderstanding something. Why is this example still retaining memory afterwards?
edit:
You could also create a new project: iOS -> Game -> Game Technology: SceneKit
Then add this into viewDidLoad:
for(int r=0;r<999999;r+=1){
SCNNode *tn=[SCNNode node];
tn=nil;
}
The memory will peak at 550MB and go down to 300MB which would be to much if there objects were fully released and removed from the RAM.
Don't rely on NSString for memory diagnostics. It has fairly atypical behavior.
This is a not-uncommon scenario, one that I've seen on S.O. more than once, that in an attempt to reduce some complicated memory problem to something simpler, the developer creates a simplified example using NSString, unaware that choosing that particular class introduces curious, unrelated behaviors. The new "Debug Memory Graph" tool or the old tried-and-true Instruments (discussed below) is the best way to diagnose the underlying issues in one's code.
As an aside, you talk about releasing objects immediately. If your method doesn't start with alloc, new, copy or mutableCopy, the object returned will not deallocated immediately after falling out of scope, because they're autorelease objects. They're not released until the autorelease pool is drained (e.g., you yield back to the run loop).
So, if your app's "high water" mark is too high, but memory eventually falls back to acceptable levels, then consider the choice of autorelease objects (and/or the introducing of your own autorelease pools). But generally this autorelease vs non-autorelease object distinction is somewhat academic unless you have a very long running loop in which you're allocating many objects prior to yielding back to the run loop.
In short, autorelease objects don't affect whether objects are deallocated or not, but merely when they are deallocated. I only mention this in response to the large for loop and the contention that objects should be deallocated immediately. The precise timing of the deallocation is impacted by the presence of autorelease objects.
Regarding your rapid memory increase in your app, it's likely to be completely unrelated to your example here. The way to diagnose this is to use Instruments (as described in WWDC 2013 Fixing Memory Issues). In short, choose "Product" - "Profile" and choose the "Leaks" tool (which will grab the essential "Allocations" tool, as well), exercise the app, and then look at precisely what was allocated and not released.
Also, Xcode 8's "Debug Object Graph" tool is incredibly useful, too, and is even easier to use. It is described in WWDC 2016's Visual Debugging with Xcode. With this tool you can see a list of objects in the left panel, and when you choose one, you can see the object graph associated with that object, so you can diagnose what unresolved references you might still have:
By the way, you might try simulating a memory warning. Cocoa objects do all sorts of caching, some of which is purged when there's memory pressure.
If you turned on any memory debugging options (e.g., zombies) on your scheme, be aware that those cause additional memory growth as it captures the associated debugging information. You might want to turn off any debugging options before analyzing leaked, abandoned or cached memory.
Bottom line, if you're seeing growth of a couple of kb per iteration and none of the objects that you instantiate are showing up and you don't have any debugging options turned on, then you might not need to worry about it. Many Cocoa objects are doing sundry cacheing that is outside of our control and it's usually negligible. But if memory is growing by mb or gb every iteration (and don't worry about the first iteration, but only subsequent ones), then that's something you really need to look at carefully.
I am having few issues on iPad app, related to CoreData.
This time regarding deleting of object.
Looking at instruments (allocation template) I found that my deleted object stays in memory forever, or at least 7hours, the time I left instruments on. Also the leak instruments doesn't show anything about.
I double check, after saving the context, both the table view which is not displaying the object among its row, and the database itself, that has physically a missing row.
I am not able, with instruments, to tell who is keeping a reference to it, preventing the object to be deallocated.
I am using ARC, and an NSFetchedResultsController is managing the UITableView.
Do you have any guess, or suggestion about what instruments to use.
You shouldn't worry about that. If you try to access the object, core data will give you an exception telling you it couldn't fulfill a fault for that object. The object is gone from your application's database. Core data's internal work might keep a reference to it for other purposes, but that purpose is out of your control.
I can't found any reference about Blocks and Garbage Collection; even the "Apple Bocks Reference" doesn't mention anithing about it (just few notes).
I never developed using blocks in a GC enviroment and I would like to know how it works, what is supported and how much "automatic" is the whole process.
Thanks in adv.
As an implementation optimisation blocks are initially stack allocated; this means you can pass them down the stack without issue.
However should you wish to pass them up the stack (as return values) or store them they must first be copied to the heap. Once on the heap normal memory management rules apply, whether you are using MRC, GC or ARC - so they work fine under GC.
To copy them onto the heap you must use block_copy() (or [ copy]) if you are using GC or MRC; under ARC provided you don't cast away the type (e.g. by assigning to a variable of type id) then the block_copy is automatic when storing into a strong variable or returning from a function - but calling it causes no harm so if in doubt you can call it.
There's a reason Garbage Collection isn't discussed in newer documentation, and it isn't that Garbage Collection is too new.
Watch WWDC 2012 session 101, from 1:13:00—1:14:10. This session is under NDA, but you will not use Garbage Collection after watching 70 seconds of that session. (And I'll update this answer once the details go public, which they should when Mountain Lion ships.)
Also, see Chris Lattner's post here. Chris Lattner works for Apple, and posted this before WWDC.
Bottom line:
Don't use garbage collection.
If you're using garbage collection, you'll want to migrate once Xcode 4.4 comes out.
When you do a release, you do not immediately remove the memory. I used this code and I can see the memory before and after the use of release and it do not change. Ok, it will be release after some time.
But, what can I do for release all memory I can before start a library that will use a lot of memory? Or how can I immediately release memory?
Memory Management is a big thing in iOS but this tidbit of information helped me a lot during my development.
"Each object has a "retain count" which is increased by calling "retain" and decreased by calling "release". Once the retain count hits 0, the object is released and the memory can be used for something else.
You can "autorelease" objects. This means the retain count isn't immediately decreased, but is decreased the next time the current autorelease pool is drained.
iOS apps have an event loop in which your code runs. After each iteration of the event loop, the autorelease pool is drained. Any object with a retain count of 0 is released.
By default, autoreleased objects are returned by methods that don't begin with new, copy, mutableCopy, retain or init. This means you can use them immediately but if you don't retain them the object will be gone on the next iteration of the run loop.
If you fail to release retained objects but no longer reference them then you will have a memory leak, this can be detected by the leaks tool in Instruments.
One strategy is to autorelease everything returned by the above named methods and store objects in retain properties (or copy for strings). In your object's dealloc method, set all your properties to nil. Setting a retain/copy property to nil releases the object that it currently points to. As long as you don't have any circular references (avoided by not using retain properties for "parent" objects such as delegates), you will never encounter any leaks."
here is the link to the thread for this information
http://www.quora.com/What-is-the-best-way-to-understand-memory-management-in-iOS-development
It's a good thread with some useful code examples as well as other references.
Release frees the memory immediatly (assuming it's the last release). That means, it can be used by your application again when allocating.
Note that every applications have some chunks (pages) of free memory assigned by system and when allocating/deallocating part of a page, the released memory is not returned automatically to the system. It's just marked as free and can be used again by the application.
To understand all this, you need to learn something about how operating systems handle memory allocation, virtual memory etc.
I want to cache the instances of a certain class. The class keeps a dictionary of all its instances and when somebody requests a new instance, the class tries to satisfy the request from the cache first. There is a small problem with memory management though: The dictionary cache retains the inserted objects, so that they never get deallocated. I do want them to get deallocated, so that I had to overload the release method and when the retain count drops to one, I can remove the instance from cache and let it get deallocated.
This works, but I am not comfortable mucking around the release method and find the solution overly complicated. I thought I could use some hashing class that does not retain the objects it stores. Is there such? The idea is that when the last user of a certain instance releases it, the instance would automatically disappear from the cache.
NSHashTable seems to be what I am looking for, but the documentation talks about “supporting weak relationships in a garbage-collected environment.” Does it also work without garbage collection?
Clarification: I cannot afford to keep the instances in memory unless somebody really needs them, that is why I want to purge the instance from the cache when the last “real” user releases it.
Better solution: This was on the iPhone, I wanted to cache some textures and on the other hand I wanted to free them from memory as soon as the last real holder released them. The easier way to code this is through another class (let’s call it TextureManager). This class manages the texture instances and caches them, so that subsequent calls for texture with the same name are served from the cache. There is no need to purge the cache immediately as the last user releases the texture. We can simply keep the texture cached in memory and when the device gets short on memory, we receive the low memory warning and can purge the cache. This is a better solution, because the caching stuff does not pollute the Texture class, we do not have to mess with release and there is even a higher chance for cache hits. The TextureManager can be abstracted into a ResourceManager, so that it can cache other data, not only textures.
Yes, you can use an NSHashTable to build what is essentially a non-retaining dictionary. Alternatively, you can call CFDictionaryCreate with NULL for release and retain callbacks. You can then simply typecast the result to a NSDictionary thanks to tollfree bridging, and use it just like a normal NSDictionary except for not fiddling with retain counts.
If you do this the dictionary will not automatically zero the reference, you will need to make sure to remove it when you dealloc an instance.
What you want is a zeroing weak reference (it's not a "Graal of cache managing algorithms", it's a well known pattern). The problem is that Objective C provides you with zeroing weak references only when running with garbage collection, not in manual memory managed programs. And the iPhone does not provide garbage collection (yet).
All the answers so far seem to point you to half-solutions.
Using a non-reataining reference is not sufficient because you will need to zero it out (or remove the entry from the dictionary) when the referenced object is deallocated. However this must be done BEFORE the -dealloc method of that object is called otherwise the very existence of the cache expose you to the risk that the object is resurrected. The way to do this is to dynamically subclass the object when you create the weak reference and, in the dynamically created subclass, override -release to use a lock and -dealloc to zero out the weak reference(s).
This works in general but it fails miserably for toll-free bridged Core Foundation objects. Unfortunately the only solution, if you need to to extend the technique to toll-free bridged objects, requires some hacking and undocumented stuff (see here for code and explanations) and is therefore not usable for iOS or programs that you want to sell on the Mac App Store.
If you need to sell on the Apple stores and must therefore avoid undocumented stuff, your best alternative is to implement locked access to a retaining cache and then scavenge it for references with a current -retainCount value of 1 when you want to release memory. As long as all accesses to the cache are done with the lock held, if you observe a count of 1 while holding the lock you know that there's no-one that can resurrect the object if you remove it from the cache (and therefore release it) before relinquishing the lock.
For iOS you can use UIApplicationDidReceiveMemoryWarningNotification to trigger the scavenging. On the mac you need to implement your own logic: maybe just a periodical check or even simply a periodical scavenging (both solutions would also work on iOS).
I've just implemented this kind of thing by using an NSMutableDictionary and registering for UIApplicationDidReceiveMemoryWarningNotification. On a memory warning I remove anything from the dictionary with a retainCount of 1...
Use [NSValue valueWithNonretainedObject:] to wrap the instance in an NSValue and put that in the dictionary. In the instance dealloc method, remove the corresponding entry from the dictionary. No messing with retain.
My understanding is that you want to implement the Graal of cache managing algorithms: drop items that will no longer be used.
You may want to consider other criteria, such as dropping the least recently requested items.
I think the way I would approach this is to maintain a separate count or a flag somewhere to indicate if the object in the cache is being used or not. You could then check this when you're done with an object, or just run a check every n seconds to see if it needs to be released or not.
I would avoid any solution involving releasing the object before removing it from the dictionary (using NSValue's valueWithNonretainedObject: would be another way to accomplish this). It would just cause you problems in the long run.