How to Implement a Salami Memory Allocator in C?

Click For Summary
SUMMARY

The discussion focuses on implementing a Salami Memory Allocator in C, which involves creating a custom memory management system. The key functions include init_allocator(), which reserves a specified amount of memory, and my_malloc(), which allocates memory from this reserved pool without freeing it. The allocator must track memory usage with pointers and ensure that requests exceeding available memory return NULL. The implementation should avoid using standard library functions directly in my_malloc() and instead manage memory from a single large allocation.

PREREQUISITES
  • Understanding of C programming language
  • Knowledge of dynamic memory allocation and pointers
  • Familiarity with memory management concepts
  • Experience with function implementation in C
NEXT STEPS
  • Implement a complete my_free() function to manage memory deallocation.
  • Explore memory alignment techniques to optimize memory usage.
  • Research error handling in memory allocation, particularly with malloc().
  • Study the implications of undefined behavior in C programming.
USEFUL FOR

C developers, software engineers focused on systems programming, and anyone interested in custom memory management techniques.

carl123
Messages
55
Reaction score
0
Salami Allocator

In this warm-up submission you will write a totally trivial allocator:

The function init allocator() reserves a given portion of memory for the allocator. Every call to my_malloc() cuts off the requested amount of memory from the remainder of the reserved memory. The call to my_free() does not free any memory. When all the memory has been used, and no more memory is left, subsequent calls to my_malloc() return NULL. For the implementation all you need is a pointer to the beginning of the remaining memory. Whenever memory is allocated, advance the pointer, until you reach the end.
C:
int memAvail;  // amount of memory to be made available to allocator

unsigned int init_allocator(unsigned int _basic_block_size, unsigned int _length){

/* This function initializes the memory allocator and makes a portion of
   ’_length’ bytes available. The allocator uses a ’_basic_block_size’ as
   its minimal unit of allocation. The function returns the amount of
   memory made available to the allocator. If an error occurred,
   it returns 0.
*/

if (_basic_block_size < _length){
    memAvail = _length/_basic_block_size;
    return memAvail;
}
else{

    return 0;
  }

}

void *my_malloc(size_t _length) {
 
 /* This preliminary implementation simply hands the call over the
     the C standard library!
     Of course this needs to be replaced by your implementation.
  */
 
 int *ptr;
  ptr = (int *) malloc(_length * sizeof(_length));
      return ptr;
  if (_length >= memAvail){
   return NULL;
 }
     return malloc(_length);
}
This my interpretation of the problem so far. It seems right to me but I don't know if I'm doing something wrong. Any help will be appreciated.
 
Last edited by a moderator:
Technology news on Phys.org
carl123 said:
Salami Allocator

In this warm-up submission you will write a totally trivial allocator:

The function init allocator() reserves a given portion of memory for the allocator. Every call to my_malloc() cuts off the requested amount of memory from the remainder of the reserved memory. The call to my_free() does not free any memory. When all the memory has been used, and no more memory is left, subsequent calls to my_malloc() return NULL. For the implementation all you need is a pointer to the beginning of the remaining memory. Whenever memory is allocated, advance the pointer, until you reach the end.
C:
int memAvail;  // amount of memory to be made available to allocator

unsigned int init_allocator(unsigned int _basic_block_size, unsigned int _length){

/* This function initializes the memory allocator and makes a portion of
   ’_length’ bytes available. The allocator uses a ’_basic_block_size’ as
   its minimal unit of allocation. The function returns the amount of
   memory made available to the allocator. If an error occurred,
   it returns 0.
*/

if (_basic_block_size < _length){
    memAvail = _length/_basic_block_size;
    return memAvail;
}
else{

    return 0;
  }

}

void *my_malloc(size_t _length) {
 
 /* This preliminary implementation simply hands the call over the
     the C standard library!
     Of course this needs to be replaced by your implementation.
  */
 
 int *ptr;
  ptr = (int *) malloc(_length * sizeof(_length));
      return ptr;
  if (_length >= memAvail){
   return NULL;
 }
     return malloc(_length);
}
This my interpretation of the problem so far. It seems right to me but I don't know if I'm doing something wrong. Any help will be appreciated.
I don't think your implementation is what the problem is calling for. My reason for thinking this is that your my_malloc() function is not much more than a wrapper around the standard library function malloc().

As I interpret this problem, you need to allocate a reasonably large chunk of memory, possibly from stack memory using an array. Your my_malloc() function should process requests for storage out of this memory pool, keeping track of the section of memory that is being used. You should also return the memory when it is no longer needed, by implementing a my_free() function that makes the formerly used memory available again.
 
Mark44 said:
As I interpret this problem, you need to allocate a reasonably large chunk of memory, possibly from stack memory using an array. Your my_malloc() function should process requests for storage out of this memory pool, keeping track of the section of memory that is being used..
I would use the normal malloc once in the initialization to get this memory.
You also have to store the parameters of the initialization function to use them in the my_malloc() function.
You should also return the memory when it is no longer needed, by implementing a my_free() function that makes the formerly used memory available again.
The exercise says "The call to my_free() does not free any memory". Keeping track of which blocks are freed would make this much harder.
 
When you by process cured meat that comes in a large chub, you often want to make sandwiches with it at home. So the store has a slicing machine with a large round blade. They whack off as many slices from the chub and as thick or thin as you want. This is why the algorithm is called a salami allocator.

So. A salami allocator does this:
Code:
1. get a large chub of memory.  Use malloc().  Check the return code from malloc().  Important!
     a. Remember the start of the chub as a pointer - call it keepme.  This means storage for the 
          pointer has to stay "live", maybe in static or global memory.
     b. Remember the end of the chub - call it  the_end. (keepme + size) 
          This means storage for the pointer has to stay "live", maybe in static memory.
2. create a "blade" - a pointer in memory that keeps moving, starting from the beginning of the chub.  Call it blade, keep in non-volatile (static) memory
3. Every request for another slice of memory:
    a. check to see if your slice is small enough to be taken from the chub -
        i.e., check to see if adding the size of the slice to blade goes past the_end.
    b. if not,  copy blade to a temp pointer, add the size to blade, return temp - this is a single slice.
    c. if the request is too big or there is no more chub left, return null.
4. When everything is done (you decide what "done" means here) , call free() using keepme.  
      keepme should never change until you do this.
So there are lessons in here:
Code:
1. watch out where you ask the program to store variables. 
       Memory in a function is created on the stack, then destroyed when the function ends.

2. if keepme was declared as an automatic variable in a function, the whole program 
    would bomb or freeze - this is called undefined behavior. Undefined behavior means the 
    program can do anything - stack dump, reformat a disk, call Marios and order a pizza.  
    Anything.  
    Most modern compilers favor option one, which is to cause the program to abort somehow, 
     hopefully harmlessly.  Some aborts can cause a kernel panic (crash) on 
    older multiprocessing systems.  So then you have 50 other users mad at you.  
    Got the point?  If your compiler does option #3 feed them the pizza. 
 
3. When you get more experience you will find that keeping your never-to-lose variables in 
    a struct makes housekeeping simpler.
 
Thanks for the input everyone. All your suggestions have given me a clear idea of what I'm supposed to do. Appreciate it
 

Similar threads

Replies
16
Views
6K
  • · Replies 8 ·
Replies
8
Views
5K
  • · Replies 19 ·
Replies
19
Views
6K
  • · Replies 17 ·
Replies
17
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 15 ·
Replies
15
Views
7K
  • · Replies 7 ·
Replies
7
Views
3K
  • · Replies 26 ·
Replies
26
Views
4K
  • · Replies 16 ·
Replies
16
Views
5K
Replies
3
Views
4K