|
From: Nicholas N. <nj...@cs...> - 2005-05-21 19:06:52
|
On Thu, 19 May 2005, Mark Stemm wrote:
> That version behaves properly, but this modification (walking each
> buffer after it's been allocated) does not:
>
> #include <stdlib.h>
> #include <string.h>
>
> int main(int argc, char **argv)
> {
> int len = 0;
> char *data = NULL;
> int do_copy = 1;
> for(int i=0; i<2000; i++) {
> len += 4096;
> char *data = (char *) malloc(len*sizeof(char));
> for (int j=0; j<len; j++) {
> data[j] = j;
> }
> free(data);
> }
> return 0;
> }
>
> Some nonscientific analysis (i.e. watching "top" while valgrind is
> running) indicates that the memory usage is initially stable, then
> quickly climbs as the buffer gets larger.
I just looked at this. Turns out that under Valgrind, on my machine (and
presumably yours) a lot of those allocations are failing -- you should be
checking the result of malloc.
I think the problem is this: the program allocates a 4KB block, then
frees it. Valgrind puts this block on its free list. The program then
allocates an 8KB block. There's no block on the free list which is 8KB or
greater, so Valgrind allocates new memory. And so on. So Valgrind's free
list ends up holding blocks of size 4KB, 8KB, 12KB, 16KB, etc. Huge
amounts of memory quickly get heldon the free list, but none of the blocks
are ever big enough to satisfy the requests.
Basically it's a pathological case for Valgrind's allocator. Mark, did
you come up with your original program (the realloc one) based on
behaviour you saw with a real application, or were you just experimenting?
N
|