I am running a subroutine which will have some implications on the memory occupied in the given time frame and has the capability to crash the app.
I am wondering if there is a macro that can force the app to disable ARC just for that particular block of code in a single file (similar to how you would implement native assembly instructions in a block of code).
I always believed that the runtime automatically initializes all properties with nil when an object is created.
But the release build for the App Store is different than the debug build during development. I have heard Xcode creates more stable builds for debugging with various security check mechanisms around variables and properties that prevent crashes but bloat up the code.
When you build for distribution, so is the myth, compiler optimizations strip out this "unnecessary" debug code to make the code faster.
I have already experienced mysterious bugs that suddenly happened in release builds.
But now a developer also told me this: In the release build, the runtime does NOT set the properties to nil. They are uninitialized. Their value is garbage memory, unless you do it manually. So !foobar is not safe to check unless you initialize the properties with nil.
So far all my apps always assume properties are nil unless I set an object.
Is this correct or does the runtime still initialize our properties to nil when we create an object?
The developer in question is wrong and you should hold any other "advice" they've given you as highly suspect.
All instance variables, including those synthesized by #property, will always be zeroed out on allocation by the Objective-C runtime. This has been the defined, documented, behavior of the Objective-C runtime since the language's inception.
Static variables will always be initialized to zero/nil/NULL, too. Local variables will be uninitialized under manual-retain-release and initialized to zero/nil/NULL when using ARC.
There are two key differences between DEBUG and RELEASE builds:
the linker will strip away any debugging symbols. This makes the code harder to debug, but makes the executable considerably smaller.
the optimizer will optimize for code size and speed.
It is that second one that causes the "mysterious" changes in behavior between DEBUG and RELEASE. The optimizer will re-use stack space and re-order operations in the code (that can be re-ordered; method calls cannot, for example) as necessary to make the code faster and smaller. This tends to uncover bugs that exist in DEBUG builds, but aren't tripped because the compiler isn't moving stuff about on the stack.
You'll be fine assuming nil.
The compiler doesn't really do anything different in release builds - I think it strips out debug stuff (NSLogs, breakpoint handlers, exception pausing, etc.) only.
When i build my app with any optimization level other than -o0, the application crashes at some point because of EXC_BAD_ACCESS. I tries all possible optimization levels (-o1/2/3/s) and all crashes the application.
The compiler is LLVM 3.0.
Any idea why it happens? Is this some known issue?
I would check for uninitialized variables as a possible cause. The different settings causes things to move around and something that is "safe" in the unoptimized build could hold a stale pointer in another.
Summary: Can you add to my checklist of things to watch out for when migrating to iOS 5? StackOverflow has been invaluable as I've worked on upgrading to iOS 5. I've discovered some pretty basic things I'd missed prior to Xcode 4.2, and I'm wondering what other "gotchas" might be lurking.
Detail: With iOS 5 shipping this week, I've had to make some changes to a couple of my apps. Xcode 4.2 does a much better job analyzing memory management code because of the new ARC feature. The iOS 5 update is a great point at which to review all your memory management code. The new compiler also finds a number of other issues that earlier compilers missed. Kudos to the Apple compiler engineers. Here are the main things that have helped (and many of them will also apply to earlier versions of iOS).
Make sure to call [super dealloc] at the END of your dealloc methods, not the beginning.
In viewDidUnload, some people have reported bugs that require [super viewDidUnload] to be called at the end, not the beginning, of your viewDidUnload.
Understand retain counts, synthesized setters, and when to call release or autorelease. The new compiler will point out more problems than the older compilers did. (I thought I'd been careful, but apparently I wasn't careful enough.) Apple's memory management guide is required reading -- no shortcuts.
It's a good idea to turn on zombies when debugging (in Xcode, choose Product | Edit Scheme... and select the Debug scheme; on the Diagnostics tab, check Enable Zombie Objects). This can help you find attempted uses of zombies (objects you shouldn't be using any more).
The Leaks instrument is also helpful. Run your app in Profile mode and choose the Leaks template. In the Instruments window, select the Leaks instrument and check the box that says "Gather Leaked Memory Contents" and it will help you see where the leaked memory originates in your code.
There are a few odds and ends I've encountered:
Apple's singleton pattern needs "oneway" added to the return type declaration:
- (oneway void) release { }
You may need to manually add "armv6" as an architecture type in your Build Settings (and be sure Build Active Architecture Only is set to NO).
Any other suggestions of potential pitfalls I should look for? I have a feeling that my apps are more stable now, but I felt pretty good about them before.
1/ Modal controllers behave differently, if you were changing their size. If you need modal dialog of a different size, consider using iOS 5 child view controllers.
2/ For a table, if you were returning nil section header and positive height, in iOS 4, the header was hidden. In iOS 5, you have to return zero height for nil headers.
3/ UDID is deprecated. You can use CFUUIDCreate to create a unique id and save it into your settings but be aware that a device data can be backed up and then restored to another device, leaving you with two devices with the same id. I solved the situation by saving my id into keychain with attribute kSecAttrAccessibleWhenUnlockedThisDeviceOnly.
About your list:
[super viewDidUnload] should be always called as the last statement in your viewDidUnload. The logic is the same as in [super dealloc]. Note, that you should also call [self viewDidUnload] in your dealloc (if you don't already release your memory there) because it is not called implicitly (although sometimes it is).
From my experiments, leak detection in Instruments don't report leaks on properties which are synthesized without assigning a property name.
I'm getting the following exception when I run my application in Release mode from Visual C++.
Unhandled Exception:
System.AccessViolationException:
Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt. at
_cexit() at .LanguageSupport._UninitializeDefaultDomain(Void
* cookie) at .LanguageSupport.UninitializeDefaultDomain()
at
.LanguageSupport.DomainUnload(Object
source, Eve ntArgs arguments) at
.ModuleUninitializer.SingletonDomainUnload(Objec
t source, EventArgs arguments)
This doesn't happen in Debug mode. Initially, I saw this exception on my home computer, but not work computer. When I continued to develop on my work computer, I ended up bumping into it.
Also, I found that when I added three const std::string variables the exception was thrown. If I removed then then all went well.
Another piece of information: I've found that turning off all the compiler optimizations in Release mode makes the exception go away
Something fishy is going on. Any ideas on how to track this down?
Thanks for the help,
Joe
Joe, you have a memory leak.
You're probably trying to use some memory that has been deleted.
See this article for common causes of memory leaks, and how to identify them, otherwise, search for "C++ memory profiler" + your compiler/platform, it'll give links to Memory profilers suitable for your compiler and platform, these will help track down the memory leak by watching how your program uses memory as it runs.
Hope this helps.
EDIT
How to track it down? This is off the top of my head, there may be better advice else where . . .
Find where the code crashes, it'll be when accessing the contents of some pointer (or deleting a pointer).
The problem is that that pointer has either a) never been assigned b) is already deleted.
Go through all references to pointers of that type, are they used in copy ctors/assignment operators?
If so, are it's contents being copied or just the pointer?
If just the pointer then is the containing class trying to delete the pointer? If so the first class to die will succeed, the second will throw an access violation.
If you don't explicitly code copy ctors and operator=, then you should hide them (declare private prototypes but don't implement them), this stops the compiler from generating default implementations for you.
When you hide them you'll get compiler errors everywhere they're being used, it might be that you can clean these up, or that you need to implement the copy ctor and operator= for each class.
I'm on vacation from tomorrow or two weeks, email me direct today (follow the link on my SO user page) if you've any questions on this.
Do you have any code that is #defined out for debuging in your code?
i.e.
#ifndef _DEBUG
//release only code such as liscensing code
#endif
That's one thing that could be causing the problem, and I've run into it before as well.
Another possibility is a VS issue (or whatever IDE you're using).
Try running the release .exe directly instead of through the develoment environment and see if you still have the same issue.
It's a while since I've done C++ "in anger" so to speak, so some (or indeed all) of what I say below may well be out of date.
Are you using managed C++? If not then it sounds like an uninitialised pointer. It used to be the case that all pointers were nulled in debug & I recall something about turning this behaviour off, but I can't remember the full details right now.
Are the strings overrunning their variables? Unlikely with std::string, but worth eliminating.
Couple of possibilities:
I would guess that you are reading/writing past local array end. In debug builds this may work, as memory is not tightly allocated. In release builds this is more likely to cause problems, depends on what is allocated right next to the array.
Another possibility is that you have an uninitialized pointer somewhere. VC default initializes local variables in debug mode, but not in release mode. Thus code like:
int* p;
if (p != NULL) { /* do something */ }
Typically fails on release mode.
The error message is strongly suggesting you have a memory issue, probably overwriting memory. These are hard to find, but you can find some possible solutions googling "visual c++ memory corruption tool".
The thing about memory corruption is that it's unpredictable. It doesn't necessarily have any consequences, and if it does they may not result in a crash. Crashing like that is good, because it informs you you've got a problem.
Fiddling with debug vs. release, adding or removing parts of code, changing optimization options and the like is unlikely to solve the problem. Even if it does, it's likely to crop up if any changes are made.
So, you've got a memory corruption problem. Those are almost always difficult to find, but there are tools. You need to fix that problem.
You might also look at your shop practices. Do you use less safe constructs (new arrays rather than vector<>, say)? Do you have coding standards to try to reduce risk? Do you have code reviews? Memory corruption can be insidious and damaging, and you want to avoid it as much as possible.
What your getting is a system exception from the OS. These are not handled because they are not C++ exception. However you can convert then into a C++ exception and catch them like a normal exception.
There is a great article here http://www.thunderguy.com/semicolon/2002/08/15/visual-c-exception-handling/ (page 3) that shows how to create a Windows Exception class that will catch the exception using the _set_se_translator method and throw a C++ exception. The great thing is you can get a stack from the EXCEPTION_RECORD structure, although your'll have to add that functionality to process the structure, but it will help narrow your search for that access violation.
I think the issue here is uninitialized local variable.
In Debug mode generally the variables get initialized and you don't get any exceptions.
But errors may occur in release mode because of this.
Try to look for uninitialized variable whose access may cause exception.
Suppose you have boolean local variable.
bool bRet;
In debug build bRet will get initailized to 0 and your code just works fine .
But in release it won't be 0 , it would be some random value and your code might be doing something based on bRet .It may later cause an exception because bRet value is wrong.