On Wed, Feb 20, 2013 at 3:50 PM, Ivan Vučica <address@hidden> wrote:
On 20. 2. 2013., at 19:00, Jamie Ramone <address@hidden> wrote:
On Wed, Feb 20, 2013 at 2:20 PM, Ivan Vučica <address@hidden> wrote:
Most of the losses seem to be in GSPrivateBuildStrings().
http://svn.gna.org/svn/gnustep/libs/base/trunk/Source/externs.m
which says it's called from +[NSObject initialize] solely to optimize
existing global constant strings.
So that's alright; you don't want these released until the end of the
program, and perhaps not even then. In a discussion from, I think, a year
ago, David advocated avoiding deinitalization and releasing of as much
stuff at the end of the program as realistically possible. Imagine
allocating a gigabyte of small objects. Instead of deallocing them, you
simply leave them be. They'll get deallocated at the end of the program,
and you'll avoid potentially swapping a gigabyte of virtual memory from
disk into RAM. So I guess that not bothering to use something like C++
destructors or something with atexit() to hack deallocing at the end of the
program is the result of this (good and smart) opinion.
I'm not sure I follow the deallocation-swap argument. Why would a block of
memory that was swapped out be swapped back in when deallocating it? My
understanding is that free () simply changes some values in the c runtime
to mark that block of memory as available.
That is my understanding of free() too. The problem is not with freeing
one massive 1gb block. But imagine freeing 1gb of SMALL objects. If
-dealloc is more complex and references ivars, you need to swap them in,
free subobjects, stuff like that.
Oh, OK, I see what you mean now. Yes, that case is an obvious swap-monsoon.
However, the proper way to deal with that problem is not causing it in the
first place. Plus, main memory is progressively abundant. It gets harder
and harder to use up all the memory so as to cause even a single swap, at
least by the data structures themselves. I don't even have a swap
partition, what with having 8 GB and all. I don't know, it seems like a not
very common case.
You will have to look up the old thread, or wait for someone with more
understanding to chime in.
But be that as it may, the main problem I have with this kind of lazy
deallocation is that it makes my own memory leaks much harder to find as
they get camouflaged by these. Can this behavior be turned off in favor of
a traditional bracketed approach?
If my understanding is correct, the code isn't even there. You could write
something using a C++ destructor trick using a global variable that will
get destructed at exit no matter what (well, unless you have a very nasty
crash). But you'd have to write code to perform these free()s.
There is probably some way of telling Valgrind to ignore certain leaks,
right?
I'll check the documentation but I don't think that's possible. Valgrind
checks for alloc/free balance. While you can change the level of verbosity,
I don't think it's possible to get it to filter (what it sees as) leaks.
But like I said, I have to check the documentation just to be sure.
The only case where you want to dealloc stuff is where you do
deinitialization of network connection and similar things in
-(void)dealloc, and yesterday I ran into Apple recommendation that in clean
code you don't really want to do that in -(void)dealloc. Or should avoid it
as much as possible. I'm cargo-culting here; it sounds reasonable, but I
don't really have anything more than that.
I know, that's why I use release ;-)
You override -release to release resources at object's end-of-life? :-S
No, I release an object once I'm done using it making use of the reference
count mechanism. I'm surprised you never heard of it, it's been around for
decades :P But the reference count mechanism guarantees that -dealloc will
eventually be called, at least in theory, where we don't have this
leave-it-to-the-os hack. Which is why I have implementations of -dealloc in
my objects.
Heck, even Apple tried to push "immediate termination" in 10.7 -- probably
precisely to cut down on shutdown times! Killing an app is faster than
gracefully shutting it down.
That's fine for some desktop environments. However, I really, really,
REALLY don't care about it not shitting down instantaneously. For my
purposes, a graceful shutdown is preferred.
I like graceful shutdown too, but am also pointing out why (some of) the
leaks are not troublesome. :-)
I'm afraid I cannot help more than this. Who knows how much Valgrind would
help with Cocoa?
Yes, I see. Thanks for all the help.
Oh, BTW, about that macro, do you mean redefine it in my code or recompile
GNUstep-base?
More leaks seem to come from Unicode.m. Again, creation of a large static
table seems to be the cause, and is not cause for alarm.
Could more leaks be static constant NSStrings?
In any case, if possible, try configuring Valgrind to not treat these
strings as leaks. Or try replacing GS_REPLACE_CONSTANT_STRING's #define
with an empty define; it will cut down at least on these erroneous leak
reports.
OK, I'll try that. Thanks.
////////
However, I really can't see any LARGE block being allocated! Note that
out of those ~400kb of still alocated memory, 390kb are still reachable,
and did not get reported by Valgrind in the log you printed out. :-)
And perhaps they're not leaks at all, but are meant to be deallocated by
the death of the process; if you can't reliably notice increments in memory
usage over time, I'd say don't worry.
On 20. 2. 2013., at 17:58, Jamie Ramone <address@hidden> wrote:
Hi everyone. I'v been having a bit of a hard time with a program I'm
writing. I saw lots of memory leaks with valgrind so I reviewed everything,
fixed a few obvious mistakes and managed to reduce it to 1.2 MB of memory
lost. But after that I was stumped. I looked trough the code, Apple's and
GNUstep's (meager) documentation and nothing. I finally decided to run a
little test. I commented out the main function and replaced it with this:
int main ( int args, char ** arg )
{
int errorCode = -1;
NSAutoreleasePool * pool = nil;
pool = [NSAutoreleasePool new];
if ( pool != nil ) {
errorCode = 0;
}
[pool release];
return errorCode;
}
I ran it through valgrind and got this: