简体   繁体   中英

How malloc ask for heap memory

I have a huge array which I have allotted to heap, since it would lead to error if left on the stack. Now there are two methods to my knowledge which I could send this to the heap.

#1

int i;
int x=10000, int y=10000;
double** array=(double**)malloc(sizeof(double*)*x);
if (image) {
    for (i=0; i<x; i++) {
        array[i] =(double*)malloc(sizeof(double)*y);
    }
}

#2

double *array[x][y]=(double*)malloc(sizeof(double)*x*y);

Now I was wondering which method is superoir? I think #1 is asking for x blocks of legnth y in heap, which need not be next to each other. Where as #2 is asking for a block of y*x in heap. #2 is asking for a huge block of x*y, where as #1 is asking for blocks which don't need to be connected. So would #1 be superoir since it could be split up. Say the heap couldn't handle getting a huge stripe with length x*y could handle x amount of y stripes of data.

First is this even true? Am I missing something about either method? Is my argument even practical, or if true, is not a likely scenario? Got an even more superoir method?

Thanks for you insight.

You are correct that the first method may be more flexible because it need not find a contiguous span of free memory of the total size, whereas the second one does. A possible adverse affect of this is that this itself may cause even more fragmentation of the heap, if the slabs allocated aren't contiguous. There'll be regions of space in between each slab within which future allocations will need to find room.

The second option, however, may exploit spatial and temporal locality . Basically, since more of the data is right next to each other, there's an increased chance that the data you need will be in the CPU caches, and as a result, operating on this memory will be a lot faster.

It dependes on the memory allocator you use and the value of your x and y.

Memory allocator often cache small memory blocks in user space and handle small allocation in user space, while forwording larger allocation request to kernel via mmap .

Most memory allocators work like this:

void* malloc(size_t size)
    if (size > THRESHOLD) {
        return large_alloc(size)     // forward to mmap
    }
retry:
    void* ret = small_alloc(size);   // handled in user space
    if (ret == NULL) {               // no small blocks left
        enlarge_heap();              // map more memory from kernel
        goto retry;
    }
    return ret;
}

In your case y == 10000 so you are asking for a 80000-byte memory block. In the default memory allocator in glibc, the mmap threshold is 128kB. So this request tends to be handled in user space if the allocator already cached enough memory. But #2 would invoke an mmap call since it's larger than 128kB.

But, in your example x == 10000. So you are talking about a single mmap system call call and 10000 allocations in user space. Trust me. #2 is much more faster:

An allocation in a highly optimized allocator implementation always takes more than 70 cycles on a modern x86 machine. 10000 allocations would consume more than 700000 cycles. But an typical mmap call latency should be no more than 100000 cycles. So #2 is better.

For other allocators such as TCMalloc it's a little bit different. TCMalloc has no such threshold and always tries to handle large allocation request in user space in its Span structure. So #2 is definatly much better since it only need a single allocation.


I agree that #1 is more flexible since #2 requires the allocator to find a large contiguous memory block. But remember it is only contiguous in virtual memory, and the physical pages are mapped on-demand when you first touches it. It means it need not to be contiguous in physical memory. And it is often easy to find a 8 * 10000 * 10000 byte of contiguous memory area in virtual memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM