Is there any way to handle memory leaks in an ASOC project? My app, when run using Instruments, seems to have a lot of leaking, and I don’t really know how to fix that. In Cocoa I’d look for unreleased objects, I mostly understand how that works. But in Applescript, I never had to worry about it. I just set someVariable to “a value” and later can set someVariable with “a new value” and that was all, I figured AS just did the memory management on its own.
My app has a bunch of bound items, including several text labels that change regularly, a progress spinner, a table view that is updated with new items added as files process, buttons that enable/disable when the app is busy and can’t be stopped, etc. The code is over 500 lines so I wasn’t going to post it unless someone wanted a specific part (or all). I could also post some pix of my Instruments readout, the entire trace file is +50mb though.
Because I am facing the same problem. Just running the ASOC app and not doing anything has the Leaks instrument registering leaks all over the place.
So by “Garbage Collection enabled by default” you mean ASOC code is run garbage collected automatically or that new ASOC projects have the build setting set by default? For my project I think I had to enable it myself.
Also why would the Leaks instruments be meaningless then? Shouldn’t it account for garbage collected memory?
The leaks are registerring in +[NSBundle mainBundle] and -[NSBundle(AppleScriptObjectiveC) loadAppleScriptObjectiveCScripts] which highly suggests that the leaks are happing in my ASOC code because main.m calls [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts] before return NSApplicationMain(…)
Switching between GC enabled and non GC in the build settings has the effect that I have leaks in the hundreds (with GC) and about 7 leaks otherwise (without GC).
It’s a default setting in the project template. If it’s off, you have to do the whole retain/release thing.
I’m far from an expert on memory management, but as I understand it, in simple terms a garbage-collected app leaks like a sieve and the collector periodically goes around cleaning up the mess. So at any point in time, you might see lots of leaked memory. I would think the real matter of interest would be total memory used over a long-ish period of time.
I suspect that if you want to use Instruments, the GC Monitor would be more useful than Leaks – it should show the memory being reclaimed.
Ah, Ok I originally understood it that way. Just wanted to make sure.
It appears though that with the ASOC template that came with my Xcode 3.2.3 and iOS 4.0.2 SDK, GC is not enabled by default. So you would really have to say anobject’s release() at the appropriate times. I just enabled GC myself though.
That makes a whole lot of sense. I skimmed the Leaks instruments documentation and they didn’t mention that bit about GC so I just assumed that it would take care of that automatically. The GC monitor instrument really is favorable in this case. Though I don’t really understand how to read the statistics it spits out.
Ok I have been playing around a little bit more with Instruments.
This tool is simply awesome!
So there’s a GC template… if you go from Xcode via Run > Run with Performance Tool > GC Monitor you will launch your app with that template preselected.
In this template there’s a tool called Object Graph - this is the one that you want!
It is basically the same as Leaks just specifically for GC with it’s interconnections between objects.
If you select the Object Graph instrument in the timeline, look at the left paramater pane in the mid to bottom corner.
There’s a twirl down item there called “Block Filters” with three sub items - “Roots Only”, “Exclude Non-Objects” and “User-Defined Only”. Tick all three. If you now still see entries in the table view in the middle after all your objects should have been released (say you closed your main window but the app’s still running) then you’ve got leaks.
You need to wait a bit though for the next generational collection to happen (look at the Garbage Collection instrument) before making judgements.
The most important tick marks are “Roots Only” and “User-Defined Only”. Because you don’t want to have your user-defined root objects hanging around after all your important instances have just been kicked off the heap. If App Delegate stuff is still there somewhere (mind you: not as Root Object!) it should be fine… delegates are not considered strong objects.
Of course, as ASS apps did and ASOC apps initially do tend to go, it’s not that big of a problem if you only have one main window and the user needs to quit the app anyway after closing it - the leaked memory will be freed in that case.
Anyway, hope this helps anyone. I can wholeheartedly recommend giving Instruments a whirl.
I am developing an applescriptobjc app in xcode 5.1 and I am facing memory leaks. In particular the instruments app is registering a leak for [NSBundle(AppleScriptObjectiveC) loadAppleScriptObjectiveCScripts] in the main.m file straight after launch. How can I fix this?? I managed to prevent some other leaks releasing objects created with init, alloc etc in the applescript, but I have no idea how to fix this. What’s the problem? A solution? Btw I cannot run Garbage Collector cause I’m using xcode 5.1, so that’s not an option for me I’m afraid.
Thank you Shane. But if I may ask, what is all about? I got two other leaks in my agent app, one of them everytime I open the status menu. To be honest I tried to release objects at the end of each handler but when I do it I get a BAD ACCES warning for the main.m file. How to deal with leaks? Thank you in advance.
Btw, my app launches and runs perfectly If I don’t try to release anything. It never crushed.
When you’re letting ARC handle memory management you may never release an object yourself.
The leak you have discovered happens when the AppleScripts are loaded at launch time, it means it happens once during in the application’s entire lifetime. A reason to forget it and it’s not directly considered a leak, leaks are generally eating more memory over time. Now it’s just some extra unnecessary memory being used where no pointer points to so it can’t be freed later.
DJ’s correct, but there’s a little bit more to it for ASObjC projects, in that the memory management for ASObjC code (in 10.8+) is all handled by the bridging software. So you could, if you wanted/needed to, use ASObjC in a manually-memory-managed app – your code would not need to be any different.
Before 10.8, because ASObjC generally relied on garbage collection, the bridging software did no memory management, so using manual memory management would have required the use of retain() and release().
Thank you guys, but I got a few more questions for you. I understood that I can ignore the initial “leak”, but what about the others (two or three more)?? One occurs whenever I open the status menu (why?) and the other when I perfom a selector/action. What can I do if I cannot release objects?? And last questions, how can I decrease the amount of memory allocated at launch? Now it allocates 15MB of memory, but I really don’t get why since it’s an agent app with one menu and submenu only. Thank you.
Not much. I’m not sure if the AppleScriptObjC framework takes more attention to an object if you make it either empty, null or missing value. It’s a long shot but maybe Shane can tell you more about this.
Do you have a lot of memory installed? The initial memory of a process depends on the amount of memory installed and the amount of maximum processes that are allowed to run simultaneous. So even for small processes the initial memory can feel like overkill.
And are you sure you haven’t included preserved memory or/and virtual memory for the proces? Clear first all the preserved memory before builing/launching the application.
Do you run the process in debug mode? Debug uses much more entry points for debugging like break points, this makes the executable bigger than in release mode.
Do you compile the AppleScript files as read-only? Those are smaller as well (remember, when the application launches the whole script is loaded into the memory).
Do you make use of static libraries? Static libraries, unlike dynamic libraries, are included into you executable. This is a great when you’re not sure if the library is installed on other machines but your executable will grow exponentially and eventually using more memory.
I was always told not to worry about things that are beyond my control, and I think that’s good advice in this sort of situation. 15MB is peanuts, and if you’re just talking the bald memory figure, it’s pretty meaningless.