In other words, should a production app eliminate all logging and printing to the console to reduce memory usage (or is the memory usage negligible)?
In general logging take some very small amount of device resources but it is so small that you shouldn't feel any changes unless you are printing a whole book to console ;)
Despite of this, I would recommend to remove all your logs if they are not provide any valuable information to user. Pure debug logs could be very annoying and if someone will work with your code in future, he can call you unprofessional ;)
I will recommend removing logs in methods which are called frequently due to the nature of the app (e.g. an update method in a game loop). In such methods one println may cause noticeable stuttering.
You can use a method for logging which will print only in debug (scheme-wise) and do nothing on a release scheme.
You could keep your logs in debug builds, but you better disable them completely, there have been some apps that printed passwords, tokens to the log, which isn't the best thing to do,
Related
I'm writing an OS X launch agent (which watches, as it happens, for FSEvents);
it therefore has no UI and is not started from a bundle – it's just a program.
The relevant documentation and sample
code
illustrates persisting FS event IDs between invocations, and does so using
NSUserDefaults. This is clear the Right Thing To Do(TM).
The documentation for NSUserDefaults in the
Preferences and Settings Programming Guide
would appear to be the appropriate thing to read.
This shows only the Application and Global domains as being persistent, but (fairly
obviously) only the Application domain is writable for an application. However
the preferences in the application domain are keyed on the
ApplicationBundleIdentifier, which a launch agent won't have. So I'm at a loss
how such an agent should persist state.
All I can think of is that the Label in the launchd job can act as the
ApplicationBundleIdentifier – it at least has the correct form. But I can't see any
hint that that's correct, in the documentation.
The obvious (unix-normal) thing to do would be to write to a dot-file
in $HOME, but that's presumably not the Cocoa Way. Google searches
on 'osx daemon preferences', and the like, don't show up anything useful,
or else my google-fu is sadly lacking today. Googling for 'set application
bundle identifier' doesn't turn up anything likely, either.
NSUserDefaults:persistentDomainForName looks like it should be relevant,
but I can't work out its intentions from its method documentation.
I've found one question here which seems relevant, but while it's tantalisingly close, it doesn't say where the daemon gets its identifier from.
I've limited experience with Objective-C and Cocoa, which means that by
now I rather suspect I'm barking up the wrong tree, but don't really know where
to look next.
You can (and imo should) have an Info.plist even in a single-file executable.(see http://www.red-sweater.com/blog/2083/the-power-of-plist)
However, NSUserDefaults is a little more questionable. Conceptually, it's intended for user settings, rather than internal state. However, there's no real reason it wouldn't be suited to this, so I'd probably go ahead and do so.
I've recently converted my iOS project to ARC. I have two targets in my project. One is the application itself, and the other is a set of GHUnit tests. I have approximately 200 tests that do quite a lot of work in terms of creating and modifying Core Data objects. The Core Data store used by the tests is an in memory store, and is thrown away once the tests are finished (i.e. it is not persisted anywhere).
When my tests have been running a while (they never reach the exact same point before the error is thrown, but it is always around the same tests) the application crashes with an EXC_BAD_ACCESS (Code=2, address=...)
The output in the console is as follows:
I've followed the instructions here in this answer, and set my main.m file of the GHUnit target to use the -fno-objc-arc compiler flag, but that doesn't seem to have helped.
I don't really understand what these errors mean, and searching for them doesn't seem to have helped. My only guess is that I am running out of memory, but I'm not sure why or how, considering ARC should be releasing objects for me.
I'd really appreciate any help anyone can give me to fix this! If you have any questions just leave me a comment and I will get back to you asap!
Thanks!
Chris,
First, As you have a memory exhaustion problem, you should look at your tests running under the Instruments allocation tool. Remember to turn on VM automatic snapshots. Then you should mark the heap multiple times as the tests execute.
Second, while this may be related to ARC, it quite possibly isn't. In general, ARC apps, because they can automatically release objects sooner, have a smaller footprint than MRR apps. The move to a new compiler with different options may just be uncovering a pre-existing problem.
Third, because you are using an in-memory database, my first test would be to just change it to a SQLite DB. It can have a much smaller footprint. (While you may choose to return to in-memory DBs later, we're trying to find the cause of your memory exhaustion. An in-memory DB can use a lot of RAM. Hence, lets take is out of the equation.
Once you've done the 1st and 3rd tasks above, please report back your results.
Andrew
Well, that question may sound silly, but...
When I run my app in analyze mode or with instruments I get no possible (analyze mode) or memory (instruments) leaks.
Does it mean that my app is 100% memory leaks free ?
No. For one thing, you'd have to run every possible execution path/state sequence in your app to definitively say that there are no leaks by simple testing. More importantly, true memory leaks, where you don't release memory but no longer have a reference to it are all the leaks instrument is able to detect.
However, those are not the only similar problem you can create. You can also easily not discard data that you no longer actually need, causing memory to build up. This isn't a true leak, as you still have a reference to the data in question, it's just that you haven't released it and gotten rid of your reference to it.
You can still find this kind of problem using the allocations instrument. It won't explicitly flag problems, but it will allow you to see if you're allocating lots of memory that you don't later release. On iOS in particular, it's important to make sure that you give up allocated memory when you no longer need it, or your app's memory usage will grow until the OS terminates your app.
That really depends on how well you tested it with leaks but keep in mind that as hard as Leaks tries its not bulletproof, though if you do a through job you can be reasonably sure about your app. Don't forget to also use instruments other than leaks, the allocations tool is useful in picking up on abandoned memory which just Leaks won't point out to you but can be just as troublesome.
Your app does not run when you analyze, instead the static analyzer looks at your code. Regarding the instruments, check that your profile configuration (in edit scheme) is set to debug. Otherwise your app will be stripped out of symbols and the leaks instrument won't work.
you can assume it is in the best state now in which it could be.
I wrote an entire app, and I was just about to submit it to the app store, and in my final testing, I went back and added a few releases to ensure proper memory management was observed. And since then, I keep getting these random crashes. I've tried removing some or all of the release calls, I've tried retaining objects. I cleaned the project. I used NSZombieEnabled and that also is not helping. All this to not avail.
Most of the time, the console says provides no help. Usually the app loads, I put NSLogs in viewDidLoad, viewDidAppear, and viewWillAppear, and they all show up in the console, then it crashes.
Sometimes I also get EXC_BAD_ACCESS (and I know what that means). But its occurring randomly. So this doesn't make sense to me. Thanks for any help possible. I've written this whole app, and spent months on it. So I'm really stuck. Thank you.
Have you tried Build --> Analyze? It will search your code for leaks and other useful things you might have missed. Try that and see if it finds anything for you.
I agree with Rudy. It sounds like you're releasing something that is still in use. I would go back to the version that was working and start adding the releases one at a time til it causes the crash. Slow but effective debugging.
When you say that you "sometimes" get EXC_BAD_ACCESS, what do you get the rest of the time? Where does the crash stack indicate you're crashing? What messages do you get?
Random crashes usually indicate a timing problem. A common cause is accessing things on multiple threads. Are you? It can also mean timing differences based on network traffic.
Make sure the console doesn't indicate an exception rather than a memory violation. Usually there's something in the console that will be useful.
Options:
1) When there is bad input, the app crashes and prints a message to the console saying what happened
2) When there is bad input, the app throws away the input and continues on as if nothing happened (though nothing the problem in a separate log file).
While 2 may seem like the obvious solution, the app is an engine and framework for game development, so if a user is writing something and does something wrong, it may be beneficial for that problem to be immediately obvious (app crashing) rather than it being ignored and the user potentially forgetting to check the log to see if there were any problems (may forget if the programmed behavior isn't very noticeable on screen, so he doesn't catch that it is missing).
There is no one-size-fits-all solution. It really depends on the situation and how bad the input is.
However, since you specifically mentioned this is for an engine or framework, then I would say it should never crash. It should raise exceptions or provide notable return codes or whatever is relevant for your environment, and then the application developer using your framework can decide how to handle. The framework itself should not make this decision for all apps that utilize the framework.
I would use exceptions if the language you are using allows them..
Since your framework will be used by other developers you shouldn't really constraint any approach, you should let the developers catch your exception (or errors) and manage what to do..
Generally speaking nothing should crash on user input. Whether the app can continue with the error logged or stop right there is something that is useful to be able to configure.
If it's too easy to ignore errors, people will just do so, instead of fixing them. On the other hand, sometimes an error is not something you can fix, or it's totally unrelated to what you're working on, and it's holding up your current task. So it depends a bit on who the user is.
Logging libraries often let you switch logs on and off by module and severity. It might be that you want something similar, to let users configure the "stop on error" behaviour for certain modules or only when above a certain level of severity.
Personally I would avoid the crash approach and opt for (2) that said make sure that the error is detected and logged and above all avoid any swallowing of errors (e.g. empty catch).
It is always helpful to have some kind of tracing/logging module, for instance later when you are doing performance tuning or general troubleshooting.
It depends on what the problem is. When I'm programming and writing error handling I use this as my mantra:
Is this exception really exceptional?
Meaning, is the error in input or whatever condition is "not normal" recoverable? In the case of a game, a File not Found exception on a texture could be recoverable and you could show a default texture so you know something broke.
However, if you have textures in a compressed file and you keep getting checksum errors, that would be an exceptional exception and I would crash the game with the details.
It really boils down to: can the application keep running without issue?
The one exception to this rule though (ha ha) is, if something is corrupted you can no longer trust your validation methods and you should crash as quickly as you can to prevent the corruption from spreading.