Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using malloc/free in a tight loop

16 views
Skip to first unread message

Navaneeth

unread,
Nov 17, 2010, 4:02:17 AM11/17/10
to
My application will be looping for 5000 times. On each iteration, it
has to create a string and pass that into other methods for
processing. This string length will only be known at the runtime.

So in each iteration, this is what happens.

ptr = malloc
process(ptr)
free(ptr)

I am wondering doing frequent malloc and free is ok? Will this
fragment the memory?

My development environment is GCC and Linux. But I'd be happy to know
about the implementation in windows also.

Malcolm McLean

unread,
Nov 17, 2010, 5:12:45 AM11/17/10
to
Unlikely. When you create strings and delete strings at random you
might fragment the memory, but if you are matching allocations to
frees then the system will usually resuse the memory. (If you print
out the pointers with %p you'll probably find that you get the same
value time after time).

Unless the strings are extremely long then a modern computer isn't
going to notice allocating 5000 of them.

Navaneeth

unread,
Nov 17, 2010, 7:00:25 AM11/17/10
to
> Unless the strings are extremely long then a modern computer isn't
> going to notice allocating 5000 of them.

Thanks. My strings are not long. May be 20 characters.

So in general, can malloc fragment the memory? I was expecting the
modern implementations will be clever enough to reduce this problem.
Isn't that true?

Mikko Rauhala

unread,
Nov 17, 2010, 7:25:39 AM11/17/10
to
On Wed, 17 Nov 2010 04:00:25 -0800 (PST), Navaneeth <navan...@gmail.com>
wrote:

>> Unless the strings are extremely long then a modern computer isn't
>> going to notice allocating 5000 of them.
>
> Thanks. My strings are not long. May be 20 characters.

You know, if you have a very short maximum cap for the length, you
could just allocate that and reuse the buffer. (You could also by
default reuse the buffer and only reallocate a larger one as it
becomes necessary.)

That said, the first response was correct in that it's not likely to
make much of a difference in this quite simple case. In general though,
I would avoid unnecessary repeated allocations and frees in a tight
loop.

> So in general, can malloc fragment the memory?

In general, it can indeed. Especially if your processing step here
involves allocating space that _isn't_ freed, it can happen in your
example too, but probably not to a large extent. (The malloc
implementation just needs to be smart enough to reuse the space
left by the previous freed buffer, in the common case that it's
sufficiently large).

--
Mikko Rauhala <m...@iki.fi> - http://www.iki.fi/mjr/blog/
The Finnish Pirate Party - http://piraattipuolue.fi/
World Transhumanist Association - http://transhumanism.org/
Singularity Institute - http://singinst.org/

JohnF

unread,
Nov 17, 2010, 8:01:17 AM11/17/10
to
Navaneeth <navan...@gmail.com> wrote:
> My application will be looping for 5000 times. On each iteration, it
> has to create a string and pass that into other methods for
> processing. This string length will only be known at the runtime.
> So in each iteration, this is what happens.
> ptr = malloc
> process(ptr)
> free(ptr)
> I am wondering doing frequent malloc and free is ok? Will this
> fragment the memory?

As per MM's reply, not a problem. Nevertheless, I usually do
this kind of thing, when I very temporarily need lots of short
strings, with a short function that allocates memory from a
static array used as a wraparound buffer, something like
as follows,
#define BUFFSZ 1000 /* any size you like */
void *tempalloc(int nbytes) {
static unsigned char buffer[BUFFSZ]; /* buffer */
static int index = 0; /*start at beginning of buffer*/
void *p = NULL; /* returned ptr */
if ( nbytes <=0 || nbytes > BUFFSZ ) goto end_of_job; /* error */
if ( index+nbytes > BUFFSZ ) index=0; /* wrap buffer */
p = (void *)(buffer+index); /* ptr returned to caller */
index += nbytes; /* next ptr past returned nbytes */
end_of_job: return(p); } /* back to caller */
No need to free, or anything. You just have to be logically sure
you won't still be using the memory when it's "realloc'ed" after
the internal static buffer wraps around. (And the above code
doesn't align returned memory on anything.)
--
John Forkosh ( mailto: j...@f.com where j=john and f=forkosh )

Navaneeth

unread,
Nov 17, 2010, 8:07:18 AM11/17/10
to
>    #define BUFFSZ 1000  /* any size you like */
>    void *tempalloc(int nbytes) {
>      static unsigned char buffer[BUFFSZ]; /* buffer */
>      static int index = 0;      /*start at beginning of buffer*/
>      void *p = NULL;            /* returned ptr */
>      if ( nbytes <=0 || nbytes > BUFFSZ ) goto end_of_job; /* error */
>      if ( index+nbytes > BUFFSZ ) index=0; /* wrap buffer */
>      p = (void *)(buffer+index); /* ptr returned to caller */
>      index += nbytes;           /* next ptr past returned nbytes */
>      end_of_job: return(p); }   /* back to caller */

John,

Thanks. This seems to be a good idea. I will evaluate it.

William Hughes

unread,
Nov 17, 2010, 9:26:17 AM11/17/10
to
On Nov 17, 9:01 am, JohnF <j...@please.see.sig.for.email.com> wrote:

> Navaneeth <navaneet...@gmail.com> wrote:
> > My application will be looping for 5000 times. On each iteration, it
> > has to create a string and pass that into other methods for
> > processing. This string length will only be known at the runtime.
> > So in each iteration, this is what happens.
> >   ptr = malloc
> >   process(ptr)
> >   free(ptr)
> > I am wondering doing frequent malloc and free is ok? Will this
> > fragment the memory?
>
> As per MM's reply, not a problem. Nevertheless, I usually do
> this kind of thing, when I very temporarily need lots of short
> strings, with a short function that allocates memory from a
> static array used as a wraparound buffer, something like
> as follows,


A variant that will deal with long
strings (this is the method described
by Mikko Rauhala). The idea is malloc once and reuse
the buffer. Only realloc if you have to.

(untested, no error checking)

   #define BUFFSZ 20  /* any size you like, 2 will do */
#define MEM_INCREMENT 2 /* unless you have a good reason use 2 */

   void *tempalloc(int nbytes) {
    static void *p=malloc(BUFFSZ);
static int currbufsize = BUFFSZ;
     

while ( nbytes > currbufsize) {
curbuffsize = currbufsize*MEM_INCREMENT;
p==remlloc(p,currbuufsize);
}

return p;
}


This has the advantage of portable alignment and
it will not fail if a large allocation is requested.
It has the disadvantage that it
requires the use of the library malloc.
You can only use tempalloc safely if you are
sure that you do not need the memory from
a previous call to tempalloc any more.


A

Message has been deleted

Kenneth Brody

unread,
Nov 17, 2010, 11:51:39 AM11/17/10
to
On 11/17/2010 4:02 AM, Navaneeth wrote:
> My application will be looping for 5000 times. On each iteration, it
> has to create a string and pass that into other methods for
> processing. This string length will only be known at the runtime.
>
> So in each iteration, this is what happens.
>
> ptr = malloc
> process(ptr)
> free(ptr)
>
> I am wondering doing frequent malloc and free is ok? Will this
> fragment the memory?
[...]

Depending on what sizes you malloc, and what order you do so, and what other
memory allocating/freeing might be going on, the answer is a definite "maybe".

I might suggest a tweak to your method, however.

Keep track of the size you allocated. Then, rather than unconditionally
freeing it and allocating a new chunk, check the new size that you need. If
the current allocation is at least that large, use the current allocation.
Otherwise, free/malloc, and keep track of the new size. Then, after the
loop is finished, free the memory once and for all.

And, if you're feeling adventurous, start with a block of memory that
"should" be sufficient for "most" scenarios.

--
Kenneth Brody

Chris M. Thomasson

unread,
Nov 17, 2010, 12:26:06 PM11/17/10
to
"Navaneeth" <navan...@gmail.com> wrote in message
news:8f23500d-4a21-4412...@t35g2000yqj.googlegroups.com...

Sounds like a region allocator might help you out a bit:

http://groups.google.com/group/comp.lang.c/browse_frm/thread/97a65e8d96f6007c


pete

unread,
Nov 17, 2010, 2:03:55 PM11/17/10
to

I suspect that it might be true
of the ancient implementations as well.

Section 8.7 of the 1978 edition of The C Programming Language
describes a storage allocator system in which the freeing function,
merges the freed regions of memory, for the allocating function to use.

--
pete

Chris M. Thomasson

unread,
Nov 17, 2010, 9:13:57 PM11/17/10
to
"Chris M. Thomasson" <cri...@charter.net> wrote in message
news:xeUEo.35278$qg3....@newsfe14.iad...

> "Navaneeth" <navan...@gmail.com> wrote in message
> news:8f23500d-4a21-4412...@t35g2000yqj.googlegroups.com...
>> My application will be looping for 5000 times. On each iteration, it
>> has to create a string and pass that into other methods for
>> processing. This string length will only be known at the runtime.
>>
>> So in each iteration, this is what happens.
>>
>> ptr = malloc
>> process(ptr)
>> free(ptr)
>>
>> I am wondering doing frequent malloc and free is ok? Will this
>> fragment the memory?
>>
>> My development environment is GCC and Linux. But I'd be happy to know
>> about the implementation in windows also.
>
> Sounds like a region allocator might help you out a bit:


Or, you might be able to do something really simple like:

http://codepad.org/kTdySzAe
______________________________________________________________
#include <stdio.h>
#include <stdlib.h>


#define ITERS 128U

#define RAND() ((size_t)rand())

#define STRING_MAX_SIZE 64U

#define STRING_ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

#define STRING_ALPHABET_GET() \
STRING_ALPHABET[RAND() % (sizeof(STRING_ALPHABET) - 1)]


char*
string_populate(
char* string,
size_t* psize
){
size_t i;
size_t size = RAND() % STRING_MAX_SIZE;
*psize = size;

string[size] = '\0';

for (i = 0; i < size; ++i)
{
string[i] = STRING_ALPHABET_GET();
}

return string;
}


void
string_process(
char const* string,
size_t size
){
size_t i;

for (i = 0; i < size; ++i)
{
putchar(string[i]);
}

puts("\n_______________________________________________\n");
}


int
main(void)
{
char buffer[STRING_MAX_SIZE];
size_t i;

for (i = 0; i < ITERS; ++i)
{
size_t size;
char* string = string_populate(buffer, &size);
string_process(string, size);
}

puts("\n\n___________________________________________\n"
"The program has completed.\n");

getchar();

return 0;
}

______________________________________________________________


No need to call `malloc()/free()' and friends... ;^)


Nobody

unread,
Nov 19, 2010, 1:54:42 PM11/19/10
to
On Wed, 17 Nov 2010 04:00:25 -0800, Navaneeth wrote:

> So in general, can malloc fragment the memory? I was expecting the
> modern implementations will be clever enough to reduce this problem.
> Isn't that true?

They will try to minimise it, but it isn't always possible.

E.g.:

for (n = n0; n <= n1; n++) {
void *p = malloc(n);
void *q = malloc(1);
...
free(p);
}

Each new allocation will be 1 byte too large to fit into the space
for the previous allocation. Some of them will fit due to the previous
allocation having been oversized, but they can't all fit.

If you really need to prevent fragmentation, you need a relocating
allocator, which implies a different interface. With malloc(), any
returned pointer remains valid until free()d; the implementation can't
just move blocks as it chooses.

Gordon Burditt

unread,
Nov 20, 2010, 6:15:35 AM11/20/10
to
>has to create a string and pass that into other methods for
>processing. This string length will only be known at the runtime.
>
>So in each iteration, this is what happens.
>
>ptr = malloc
>process(ptr)
>free(ptr)
>
>I am wondering doing frequent malloc and free is ok? Will this
>fragment the memory?

If you only hold on to one string at a time, it is unlikely you
will fragment memory much. Each time through the loop, you will
go back to the state of everything freed. A "reasonable" allocator
will recombine adjacent allocations when both are freed.

For programs like you describe, it might be less time-consuming to
keep re-using the single chunk of memory as long as it's big enough,
and realloc() it larger when needed.

Here's an example of (rather horribly) fragmenting memory:

You have only 1000TB of memory for string data. You allocate
10,000,000,000,000 strings averaging 100 bytes each (including
malloc() bookkeeping overhead) and maybe ranging in size from 50-150
bytes. (Perhaps these are DNA fragments from various species.)
This just about fills up the memory. Now free() all but 10,000,000
of them, but which of the strings gets free()d and which gets kept
depends somewhat randomly on external data. There is only about
0.001 TB of memory still allocated, but the strings are scattered
all over, so good luck trying to allocate 1TB of contiguous memory,
even though you've got 1,000 times that in free memory.

Oh, yes, malloc()/free() cannot move allocated memory unless there's
a sophisticated garbage collector that can track down all references
to memory in use, including in files.

Some allocators try to avoid fragmentation by taking large requests
from one pool, and tiny requests from another, perhaps with a whole
range of power-of-two-sized blocks. That can be effective, but not
in the above case, since all of the strings were roughly the same
size.

0 new messages