Main Content

Expensive allocation in loop

Fixed sized memory is allocated or deallocated in a loop

Since R2022a

Description

This defect occurs when these conditions are met:

  • The functions malloc(), calloc(), or aligned_alloc() is called inside a loop.

  • The input for the memory allocating function is a fixed size.

  • The function free() is then called to deallocate that same memory inside the loop.

Risk

If the size of the memory is constant, allocating and deallocating memory in a loop is unnecessary and inefficient. Allocating the necessary memory once and deallocating the memory once at the end of all relevant operations is more efficient. Repeated allocation and deallocation of memory is inefficient and might lead to memory fragmentation and reduced performance.

Fix

Perform the memory allocation and deallocation outside of a loop when the memory size is constant. For instance, before entering the loop, allocate the required memory. Use the memory inside the loop. After the relevant operations are completed, deallocate the memory after the loop.

Performance improvements might vary based on the compiler, library implementation, and environment that you are using.

Examples

expand all

#include <stdbool.h>
#include <stdlib.h> 

bool keep_working(void);
void use_buffer(void*);

void Loop() {
	while(keep_working())
	{
		void* buffer = malloc(10); // Defect
		use_buffer(buffer);
		free(buffer);
	}
}
 

In this example, a buffer that has a constant size 10 bytes is allocated, used, and deallocated in a while loop. The size of the object buffer does not change in the loop. Moving the memory management out of the loop might make the code more efficient. Polyspace® flags the call to malloc().

Correction — Allocate and Deallocate Constant-Size Memory Out of the Loop

To fix this defect, move the malloc statement above the loop and the free statement below the loop.

#include <stdbool.h>
#include <stdlib.h> 

bool keep_working( void );
void use_buffer( void* );

void Loop() {
	void* buffer = malloc(10); // No Defect
	while(keep_working())
	{
		use_buffer(buffer);	
	}
	free(buffer);
}
#include <stdbool.h>
#include <stdlib.h> 

bool keep_working(void);
void use_buffer(void*);

void Loop() {
	
	while(keep_working())
	{
		void* buffer = calloc(10,4); // Defect
		use_buffer(buffer);
		free(buffer);
	}
}
  

In this example, a buffer containing 10 elements of four bytes each is allocated, used, and deallocated in a while loop. The size of buffer does not change in the loop. Moving the memory management out of the loop might make the code more efficient. Polyspace flags the call to calloc().

Correction — Allocate and Deallocate Constant Sized Memory Out of the Loop

To fix this defect, move the calloc statement above the loop and the free statement below the loop. Because calloc() allocates the memory, and then initiates all bytes to zero, the function use_buffer() expects a cleared buffer. To avoid incorrect behavior, reset the memory to zero at the beginning of the loop.

#include <stdbool.h>
#include <stdlib.h> 

bool keep_working(void);
void use_buffer(void*);

void Loop() {
	void* buffer = calloc(10,5); // No Defect
	while(keep_working())
	{
		memset(buffer,0,50);//reset the memory to zero
		use_buffer(buffer);
		free(buffer);
	}
}

Result Information

Group: Performance
Language: C | C++
Default: Off
Command-Line Syntax: EXPENSIVE_ALLOC_IN_LOOP
Impact: Medium

Version History

Introduced in R2022a