[swift-users] Why does withUnsafePointer(to:) require a var argument?

Quinn "The Eskimo!" eskimo1 at apple.com
Fri Apr 28 03:10:08 CDT 2017

On 28 Apr 2017, at 03:09, Rick Mann via swift-users <swift-users at swift.org> wrote:

> Because this runs on iOS, I'd like to reduce the amount of time I hang on to memory as much as possible (there's a lot of parallel processing happening in our pipeline). I'd also like to avoid copying the data.
> The resizing was the main reason I chose to use Data.

While I understand what you’re trying to achieve here you have to be careful that you don’t do a bunch of convoluted stuff only to find that, under the covers, the system is doing a copy for you anyway.

iOS’s memory manager, like most memory managers, will often put allocations in buckets based on their size.  Thus, reducing the size of an allocation may not actually yield a useful result.  Specifically:

* If the memory is in a zone that uses fixed sized buckets, it may not be possible to reduce the memory that you freed by reducing the size

* The system may not like wasting that much memory and actually trigger a copy [1]

The actual behaviour you get definitely varies based on the original size, the new size, and the version of the OS on which you’re running.  It may also vary based on the current state of the heap.

The upshot of this is that reducing the size of a memory block may not actually yield the results you’re looking for.  It might be better to simplify your code by:

1. Allocating one maximally sized buffer initially

2. Once you’ve read a ‘packet’ of data into that buffer, create a minimally sized data object from that and pass along to the rest of your code

3. Reuse the buffer from 1 for subsequent reads

This will always trigger a copy but a) that copy might have happened anyway, b) it will avoid wasting any memory, and c) it’s much simpler.

Share and Enjoy
Quinn "The Eskimo!"                    <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

[1] Consider this small test project:

static void test(size_t size) {
    void * buffer = malloc(size);
    void * initial = buffer;
    buffer = realloc(buffer, size / 2);
    assert(buffer != NULL);
    if (buffer == initial) {
        fprintf(stderr, "%8zu -> %-8zu didn't move\n", size, size / 2);
    } else {
        fprintf(stderr, "%8zu -> %-8zu moved\n", size, size / 2);

int main(int argc, char **argv) {
    #pragma unused(argc)
    #pragma unused(argv)
    return EXIT_SUCCESS;

When run on macOS 10.12.4 it prints:

    1024 -> 512      moved

More information about the swift-users mailing list