First, let's repair the program to detect failure of realloc.
Use a text editor to append the statement:

  if (NULL==m14) printf("FAIL line=%d\n", __LINE__);

to every line that does a realloc of m14.  For example:

  m14 = realloc(m14,(size_t)492453888); if (NULL==m14) printf("FAIL line=%d\n", 
__LINE__);

When I run it on a machine with 8GB RAM and 12.9 GB swap, it fails on line 82
and every subsequent realloc of m14.  So Tom's guess of the behavior is correct.
The test case does not handle a failure of realloc().  [This failure is
determined by glibc and the operating system, and is the _expected_ way
to say, "the system is out of space".  Memcheck handles this correctly.]

>        ...  But to go from a program that is able to
> allocate nearly 16G without valgrind to one that fails at 2.8G with
> it?

There is an interaction between realloc and memcheck that probably accounts
for this.  When the test program runs without valgrind, probably m14
soon resides at an "end" of the address space, such that each subsequent
realloc which increases the size of m14 can succeed by placing new pages
adjacent to the existing end, where the size of the new pages is about
the _difference_ between the new size and the old size.  The old data bytes
do not move; the return value of the realloc() equals the value of the
first argument.

When the test program is run under valgrind, then valgrind must allocate some
space to hold the accounting data for each block.  The accounting data is
9 bits per byte, so if a block is large then the accounting data is large.
In particular, it is plausible that the realloc(m14,...) and the accounting
data "checkerboard" the address space so that each realloc must get enough
pages for the entire new size, copy the old bytes from *m14 to the new pages,
free() the old m14, and return a pointer to the new pages.

The checkerboarding is exacerbated because memcheck does not return free()d
areas immediately to the pool of available space.  Instead, free()d areas
are "aged" for a while: put on a queue and free()d later [one at a time].
The aging allows memcheck to detect the error of access to a free()d block,
as long as the access happens while the free()d block is in the queue.
If a free()d block was re-allocated immediately by malloc(), then the bad
access to a recently-free()d block could not be detected, because the old
block was in fact [carved up and] returned by malloc().
So, memcheck causes a lag between free() and "available for use by malloc()."
The effect of this is that usage "balloons" for a while.

-- 

------------------------------------------------------------------------------
Create and publish websites with WebMatrix
Use the most popular FREE web apps or write code yourself; 
WebMatrix provides all the features you need to develop and 
publish your website. http://p.sf.net/sfu/ms-webmatrix-sf
_______________________________________________
Valgrind-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/valgrind-users

Reply via email to