Hi David - Thanks for all of that information. (FYI - I am targeting clang/linux). I suspect I will end up not pursuing this path in the end, but might make a little detour and run some experiments with profiling. The ARC interactions were surprising - thanks for that note.
-Tom > On Oct 15, 2018, at 9:57 AM, David Chisnall <[email protected]> wrote: > > On 15 Oct 2018, at 17:12, Tom Sheffler <[email protected]> wrote: >> >> I have an application that models events as objects. They are frequently >> allocated and deallocated. It occurred to me that this class might be a >> canidate for a custom allocator that allocates objects from a simple pool. >> >> I found this article (from 2010) >> https://www.mikeash.com/pyblog/friday-qa-2010-12-17-custom-object-allocators-in-objective-c.html >> that describes my situation. >> >> - objects allocated and deallocated on same thread >> - not subclassed >> - direct subclass of NSObject >> >> The gist of it is to override allocWithZone: to retrieve objects from a >> 'cache' (it could be pre-allocated, in my application). There is a line >> that sets the ISA Pointer of the new object to the class. > > It’s worth making sure you can turn this off. 90% of the time that I’ve > benchmarked code that uses a custom allocator, it runs faster if you disable > it because of fragmentation and / or interactions with threading. Often this > is code that *did* run faster with the custom allocator when it was written, > but CPUs and memory allocators became a lot faster over the years. > >> I looked through the source code to NSObject.m and libobjc2/runtime.c and it >> looks like his idea doesn't violate any assumptions. >> >> But I've been wondering a couple of things about this in the context of ARC >> and a 64-bit implementation. >> >> + (id)allocWithZone: (NSZone *)zone >> { >> id obj = GetObjectFromCache(); >> if(obj) >> *(Class *)obj = self; // set the ISA pointer to the CLASS >> else >> obj = [super allocWithZone: zone]; >> return obj; >> } > > You might want to put something in +initialize to store self in a static and > then check that self == {cached self}, falling back to the superclass > implementation. Note that now your code is about as complex as the fast path > of a modern memory allocator, so it’s unclear that it would actually make > things faster (unless you’re on GNU/Linux, because pretty much anything > outperforms glibc’s default malloc implementation). > >> >> >> 1. Is the assignment of the ISA pointer (the first slot in the object) to >> the CLASS >> still valid in 2018? With 64-bit pointers I think some bits are used for >> refcounts >> and other things. Maybe this assignment isn't safe. >> >> This article >> https://sectionfive.net/blog/2015/03/31/arc-in-depth-part-i/ >> >> says that with "tagged pointers" you need to use a function >> object_setClass(). >> >> Is that the right thing for libobjc2 and GNUstep. > > Please use object_setClass(). This is portable and will work in the future > (and will prevent clang from shouting at you). Direct assignment does > currently work, but we make no guarantees that it will continue to do so. > >> >> 2. Will this work with ARC? It seems like keeping reference counts of >> references to instances >> is independent of alloc/dealloc of objects, so it shouldn't matter. > > Maintaining the cache is difficult in ARC, because ARC does not allow > resurrection. Your code will need to be compiled without ARC and to > implement a dealloc that doesn’t call [super dealloc]. This means that > you’ll lose out on the fast paths for deallocation. You’ll also have some > odd interactions with weak pointers. I’d have to check the code to see > exactly what the failure modes will be. I think there’s now an attribute you > can stick on a class to say that it doesn’t support weak pointers - you’ll > probably want to do that. > > Oh, and do profile your code! > > David > _______________________________________________ Discuss-gnustep mailing list [email protected] https://lists.gnu.org/mailman/listinfo/discuss-gnustep
