[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Custom Allocator and 64-bit pointers, ARC
From: |
David Chisnall |
Subject: |
Re: Custom Allocator and 64-bit pointers, ARC |
Date: |
Mon, 15 Oct 2018 17:57:13 +0100 |
On 15 Oct 2018, at 17:12, Tom Sheffler <tom.sheffler@gmail.com> 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