Memory slice using malloc by slicing one big malloc'd memory

84 Views Asked by At

Consider an application that invokes malloc() and free() many times. The application allocates a total of say 1000 bytes in total.

I am trying to write a code where we reduce number of malloc / free calls by slicing one big malloc'd memory and then freeing it up:

#include <stdio.h>
#include <stdlib.h>

struct A
{
    char *s;
    int data;
};

struct B
{
    float len;
    char net;
    int data[];
};

struct C
{
    float len;
    char net;
    int data[10];
    struct B *b;
}; 

int main() {
    int s =0;
    char *p = malloc(1000);
    char *mem = p;
    //Alocate for struct A from above pool
    struct A *a = (struct A *)p;
    p += sizeof(struct A);
    struct B *b = (struct B *)p ;
    p += sizeof(struct B) + sizeof(int) * 3; //data[0]..data[2]
    struct C *c = (struct C *)p;
    free(mem);
    return 0;
}

Is this a legitimate approach for my issue? Is there any flaw in my code or scenarios that I have missed and can cause problem?

2

There are 2 best solutions below

0
Useless On BEST ANSWER

It sounds like what you're looking for is an arena allocator, and it's a perfectly normal technique in some contexts.

Once you've fixed the alignment issue, and organised your code as a deliberate and self-contained arena, you'll find

  • it doesn't fix, or easily deal with, fragmentation. So, you may end up using more memory overall depending on your allocation patterns

  • it doesn't make it any easier (or harder) to correctly match allocations to deallocations

  • it does allow you to release (or reset) the whole arena in one go, so any missing deallocations don't create permanent leaks.

    (They're still temporary leaks, in that they increase pressure & fragmentation on the arena between resets)

Sometimes it makes sense not to worry about deallocation at all, until reset. That sidesteps the first two points, but whether it is acceptable depends entirely on your allocation patterns (and how much memory you can afford to waste).

Knowing the name of the technique, it should be easy to find working examples.

1
Serge Ballesta On

You are in great risk of just adding new error sources...

While being rather low level, the malloc-free pair is designed to avoid alignment problem. That will be the first question to considere if you want to re-implement it.

Next mistakes are easy in memory addresses computation.

Those lines seem to be ok:

char *p = malloc(1000);          // ok char pointer on newly allocated memory
char *mem = p;                   // id.

struct A* a = (struct A*)p;      // ok as you are at the start of the malloc'ed block
p += sizeof(struct A);           // ok, p now points just past a

p += sizeof(struct B) + sizeof(int) * 3;  // ok,if there is no alignment problem (1)

free(mem);                                // ok, you release the full bloc

(1) actually reserved some memory for a B struct having an array data of size 3, provided p was initially correctly aligned for a B struct

This one seems far more problematic:

struct B* b = (struct A*)p + sizeof(int) * 3;//data[0]..data[2] ???

(struct A*)p will be a pointer to struct A. If you add integer values to it, you are considering it as a pointer to the initial element of an array of struct A. So b will skip 3*sizeof(int), meaning 6, 12 or 24 depending of int size, elements of size of struct A!

This code is a hint that you could let some errors sneak in your new library. Are you sure you will really trust it?