C Dynamic allocation speed question - c

I'm using this code to dynamically create a 2d array:
char **FileTables;
int rows = 1000;
int i;
FileTables = (char**)malloc(rows * sizeof(char));
for (i = 0; i < rows; i++) {
FileTables[i] = (char*)malloc(256 * sizeof(char));
}
Problem is with 1000 rows, and there could be more, it takes a couple of seconds to allocate all the memory.
Is there any faster/better method to doing this?
EDIT:
Is there an advantage to using one of these methods over the other, besides the obvious simpler code?
char **FileTables;
int rows = 1000;
int i;
FileTables = malloc(rows * sizeof(char*));
FileTables[0] = malloc(rows * 256 * sizeof(char));
for (i = 0; i < rows; i++) {
FileTables[i] = FileTables[0] + i * 256;
}
And..
char (*FileTables)[256];
int rows = 1000;
FileTables = malloc(rows * sizeof(*FileTables));
(And yes, I fixed the unnecessary casting)

You could get away with just two allocations and some pointer arithmetic:
int rows = 1000;
int cols = 256;
char *data;
char **FileTables;
int i;
data = malloc(rows * cols);
FileTables = malloc(rows * sizeof(char*));
for (i = 0; i < rows; i++) {
FileTables[i] = data + i * cols;
}
Also note that I fixed a bug in malloc(rows * sizeof(char)) (the sizeof(char) should be sizeof(char*), since you're allocating an array of pointers to char).

As long as the number of columns is constant, or if you're using C99, you can get away with a single malloc without having to do ugly row/column addressing arithmetic yourself:
char (*FileTables)[256] = malloc(rows * sizeof *FileTables);

If the array is always of the size row × 256, then you might consider a one-dimensional array malloc(row * 256), and access it in strides:
char get(unsigned i, unsigned j, char * array) { return array[j + 256 * i]; }
void set(char value, unsigned i, unsigned j, char * array) { array[j + 256 * i] = value; }
This avoids multiple allocations and gives better memory locality. On top of that, you can pick row or column ordering to micro-optimize.

char **FileTables;
int rows = 1000;
int i;
FileTables = (char**)malloc(rows * sizeof(char *));
char *data = (char *)malloc(256 * 1000 * sizeof(char));
for (i = 0; i < rows; ++i) {
FileTables[i] = data;
data += 256 * sizeof(char);
}
Should be a better solution.

I don't believe you will get anywhere near seconds. Increasing the rows to 10 million is still under a second on my machine.
However if you want to minimise allocations, you only need one.
FileTables = (char**) malloc(rows * (sizeof(char *) + 256*sizeof(char)));
FileTables[0] = (char *) &FileTables[rows];
for (i = 1; i < rows; i++) {
FileTables[i] = FileTables[i-1] + 256 * sizeof (char);
}
free(FileTables);
A more efficient way to do this is to avoid the second level of indirection.
typedef char chars[256];
int main(int argc, char** argv) {
chars* FileTables;
int rows = 100000000;
int i;
FileTables = (chars*) malloc(rows * sizeof (chars));
free(FileTables);
return (EXIT_SUCCESS);
}
This avoid a pointer lookup as the C can calculate the rest.

First of all, are you sure it's the memory allocation that is the problem? allocating 1000 blocks of memory should generally not take a few seconds.
You could look into alternate malloc implementations if you have particular needs (e.g., google's tcmalloc if you are allocating memory in threads).
Otherwise, the real "slow" part of malloc is actually getting memory from the OS (with sbrk() or mmap()), and most malloc implementations will grab a big chunk at a time and give it back in smaller pieces, so there are not 1000 calls to allocate 1k each here, there are maybe 60 calls to allocate 16k. Running the program under strace or similar may give you an idea of how many slow system calls are really being made.. You could implement similar behavior yourself, by making a single call to allocate 256K and subdividing that up into smaller chunks. You could try allocating a big chunk of memory and then immediately free()-ing it and hope that the library malloc holds onto that memory and doesn't go back to the OS for more.

This really looks like premature optimization; because, you are asking for faster, but you haven't indicated how fast is fast enough. Still, if you really need to do it this way...
Tips to speed up allocation:
Do fewer allocations
Do smaller allocations
As you can see, if you need 10M allocated, these tips soon become conflicting. To determine the right balance between smaller and fewer allocations, on needs to do profiling.
Look to your memory block size and allocate whole pages of memory at once. It's an old hardware hack, but it does guarantee that you don't ask for multiple pages of continuous memory at once (which speeds up the selecting from the free page lists), and it also guarantees that you don't waste some cycles address space by asking for addresses already reserved by the block reservation subsystem of the memory manager.
If that doesn't get you the performance you need, then rewrite the code to not require allocation the way it's been presented.
Either way, it's not possible to guarantee optimum allocation speed without detailed knowledge of how the memory management subsystem on your computer is actually designed.

Related

Where to free memory, while creating 2d array? valgrind error

I am starting to learn dynamic memory allocation. In this code, I have created in main function 2d array:
int r, c;
scanf("%d %d\n", &r, &c);
size_t row = (size_t) r;
size_t col = (size_t) c;
int **board = malloc(row * sizeof(*board));
for (int i = 0; i < r; i++) {
board[i] = malloc(col * sizeof(*board[i]));
}
(I need both int and size_t because of for loops, especially when r>=0, which is always true for size_t).
Then I change the board with other functions. Valgrind returs:
==59075== 364 (56 direct, 308 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==59075== at 0x483577F: malloc (vg_replace_malloc.c:299)
==59075== by 0x10B4DB: main (name22.c:122)
==59075==
122 line is:
int **board = malloc(row*sizeof( *board));
I suppose I have to use free(), but after checking other answers I don't know, where is my mistake and where to put free(), if use use this table through the rest of the program. I would appreciate your hints and explanations.
`
When you call int **board = malloc(row * sizeof(*board)); , the system will allocate you row * sizeof(*board) bytes of memory and then return a pointer to the start of that memory (ie - a memory address), which you are storing in the int ** variable called board.
When your program finishes, the system will reclaim that memory, so if your program is short lived, it probably doesn't matter very much, but it's good practise to get into the habit of freeing your memory because it will not reclaim any memory at all until your program exits, unless you tell it to.
For that reason, you should always call free(...), passing in the memory address you were given when you first called malloc(...), once you are done with that memory. In most cases, each call to malloc(...) should have an equal and opposite call to free(...)
This is important because your system has a finite amount of memory. If your program is asking for resources and then never giving them back when they are done you will eventually run out of memory - this is what is called a "memory leak".
So for you, calling free(...) correctly, is going to look something like this:
int **board = malloc(row * sizeof(*board));
for (int i = 0; i < r; i++) {
board[i] = malloc(col * sizeof(*board[i]));
}
// Do something with board
for (int i = 0; i < r; i++) {
free(board[i]);
}
free(board);

How to create an array of char pointer in C?

I have to create an array of char pointers each of them of size 10000000 using the best and optimized way to do this in C.
I think this will do (haven't checked for nulls though):
int i;
int num_arrays;
char **huge_char_array;
num_arrays = 10; //number of arrays you want.
huge_char_array = (char **)malloc(sizeof(char *) * num_arrays);
for(i = 0; i < num_arrays; i++)
{
huge_char_array[i] = (char *)malloc(sizeof(char) * 10000000);
}
I believe this is the optimal way because there is only one dynamic allocation, reducing overhead from fragmentation of the heap and the time taken to allocate. You can use the STRING_INDEX utility function to access the nth string.
Also, using calloc() instead of malloc() zeroes out buffer to ensure that all strings are NUL terminated.
#define STRING_SIZE 10000000
#define NUM_STRINGS 10
#define STRING_INDEX(array, string_idx) ((array) + (string_idx) * STRING_SIZE)
int main(int argc, char **argv) {
char *array_of_strings = calloc(NUM_STRINGS, STRING_SIZE);
// Access 8th character of 7th string
char c = STRING_INDEX(array_of_strings, 7)[8];
// Use array
// Free array when done
free(array_of_strings);
return 0;
}
I have been allocating 50K with each request I process this resulted in memory fragmentation. So I switched to allocate 50k * 100 = 5MB and reuse the pool when ever I need to allocate one more. If the requests increases beyond my pool capacity I double the pool size to avoid memory fragmentations. Based on this I would recommend allocating a huge chunk of memory maybe in your case 10 * 10000000 to reuse it. I am sorry but I cannot share the code that handle the pool here. Also use malloc and free and do not use new and delete.
malloc won't through exception it will simply return null if there are no memory available.
if you insist on using malloc for each element individually you can create a heap with maximum size to avoid fragmentations and in that case you will have to define the heap size.
please referee to MSDN for more details about how to create a heap and use it or the other allocation methods available for windows users.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366533(v=vs.85).aspx
char *arr[SOME_SIZE];
for(int i = 0; i < SOME_SIZE; ++i) {
arr[i] = malloc(10000000);
if(!arr[i])
// allocation failed, do something
}
Just realize that you're allocating ~9.5MB for every element in the array (i.e., SOME_SIZE * 10000000 total bytes)

Reallocation of contiguous 2D array

I am generating contiguous 2d arrays using the method posted on here by Shawn Chin.[1][2] It works very well.
Briefly from his post:
char** allocate2Dchar(int count_x, int count_y) {
int i;
# allocate space for actual data
char *data = malloc(sizeof(char) * count_x * count_y);
# create array or pointers to first elem in each 2D row
char **ptr_array = malloc(sizeof(char*) * count_x);
for (i = 0; i < count_x; i++) {
ptr_array[i] = data + (i*count_y);
}
return ptr_array;
}
And the following free function:
void free2Dchar(char** ptr_array) {
if (!ptr_array) return;
if (ptr_array[0]) free(ptr_array[0]);
free(ptr_array);
}
It is not obvious to me how to create an equivalent reallocate function in either dimension, though I am only interested in realloc'ing the number of rows while maintaining continuity. Growing the number of columns would be interesting to understand but probably quite difficult. I haven't found any direct discussion of this issue anywhere other than to say, "it's hard!".[2]
Of course this is doable by a horrible brute force method, copying the data to a new 1D array (data, above) for storage, realloc'ing the 1D array, then freeing and regenerating the pointers (ptr_array) to the row elements for the new size. This, however, is pretty slow for row modifications, since it is necessary to at least double the memory requirement to copy out the data, and this is truly horribly bad for changing the number of columns.
This is an example of said method for changing the number of rows (it wouldn't work properly for changing the number of columns because the offsets for the pointers would be wrong for the data). I haven't fully tested this, but you get the idea ...
double **
reallocate_double_array (double **ptr_array, int count_row_old, int count_row_new, int count_col)
{
int i;
int old_size = count_row_old * count_col;
int new_size = count_row_new * count_col;
double *data = malloc (old_size * sizeof (double));
memcpy (&data[0], &ptr_array[0][0], old_size * sizeof (double));
data = realloc (data, new_size * sizeof (double));
free (ptr_array[0]);
free (ptr_array);
ptr_array = malloc (count_row_new, sizeof (double *));
for (i = 0; i < count_row_new; i++)
ptr_array[i] = data + (i * count_col);
return ptr_array;
}
Plus, this method requires you know the previous size, which is obnoxious!
Any thoughts greatly appreciated.
[1] How can I allocate a 2D array using double pointers?
[2] http://www.eng.cam.ac.uk/help/tpl/languages/C/teaching_C/node52.html
The first malloc and the memcpy are unnecessary, because you have easy access to the original data array at ptr_array[0]. You don't need to know the old size, because realloc should recall how much it allocated at the address and move the correct ammount of data.
Something like this should work.
double **
reallocate_double_array (double **ptr_array, int count_row_new, int count_col)
{
int i;
int new_size = count_row_new * count_col;
double *data = ptr_array[0];
data = realloc (data, new_size * sizeof (double));
free (ptr_array);
ptr_array = calloc (count_row_new, sizeof (double *));
for (i = 0; i < count_row_new; i++)
ptr_array[i] = data + (i * count_col);
return ptr_array;
}

Array of buffers in C programming?

I am trying to create an array of buffers. I need to store an integer into each buffer. I'm not quite sure how this should be done.
int BUFFER_LENGTH = 50; //the size of each buffer
int numberOfBuffers = 10; //number of buffers
int *pBuffers; //array of buffers
pBuffers = (int *) calloc (numberOfBuffers, sizeof(int)); //make array size of numberOfBuffers
int i;
for (i = 0; i < n; i++){ //initialize each buffer to zero.
&pBuffers[i] = 0x00;
}
What is it that I am doing wrong? This code isn't really working.
You might want to allocate enough space. Right there you only allocate enough space for 10 ints; looks like you want to allocate enough for 500. The simple way is int buffers[10][50]. But if you want to calloc, you have to calloc(BUFFER_LENGTH, sizeof(int)) numberOfBuffers times.
Also, calloc automatically clears the allocated memory, so no need to do that.
#define BUFFER_LENGTH 50 /* the size of each buffer */
#define BUFFERS 10 /* number of buffers */
int **pBuffers; /* array of buffers */
pBuffers = calloc (BUFFERS, sizeof(int *)); //make array of arrays
int i;
for (i = 0; i < BUFFERS; i++) {
pBuffers[i] = calloc(BUFFER_LENGTH, sizeof(int)); // make actual arrays
}
What you're creating with your sample is an array of integers. Instead, you'll want to create an array of integer arrays. The setup is similar, but you'll need to declare the variable as an int** and allocate each buffer individually.
int **ppBuffer = (int**) calloc(numberOfBuffers, sizeof(int*));
for(int i = 0; i < numberOfBuffers; ++i)
ppBuffer[i] = (int*) calloc(BUFFER_LENGTH, sizeof(int));
There's not much point in going through and initializing the arrays to 0 since calloc will already do that for you.
Of course, the easier thing if you know the size of each buffer is going to be the constants would be to put it on the stack (and change you're int sizes to constants):
int ppBuffer[numberOfBuffers][BUFFER_LENGTH] = { 0 };
I think what your asking is for an array of arrays, which isn't what your doing here in the code, rather you've created one array.
Try something like:
#define BUFFER_LENGTH 50
#define numberOfBuffers 10
int** pBuffers;
pBuffers = (int**) calloc(numberOfBuffers, sizeof(int*));
for (int i = 0; i < numberOfBuffers; i++)
pBuffers[i] = (int*) calloc(BUFFER_LENGTH, sizeof(int));
As others said calloc initializes to 0 for you so you don't need to repeat that work. You may need to define int i outside the for loop depending on the version of C you're using.
There are some other things that can be said about style and naming conventions but one step at a time :)
I am very rusty in C, but I think you should change
&pBuffers[i] = 0x00;
to
pBuffers[i] = 0x00;
(The [i] means you are already accessing the item in location i so there is no need to add the &.)
But I might be wrong :-(

Optimal way to free() a malloc'ed 2D array in C

Supposing I have a 2 dimensional array which was created with something like this,
char **foo = (char **) malloc(height * sizeof(char *));
for(i = 0; i <= height; i++)
foo[i] = (char *) malloc (width * sizeof(char *));
First of all, Is this even the right way to create an array like this?. The catch here is, 'height' and 'width' is something that is set during runtime.
This seems to work, but which is the best strategy to free this 2d array.
free(funge) sounds wrong. Going by some other posts in here, I guess I will have free each row one by one?
I did try something like this,
for (height = 0; height < ip_ptr->funge_height; height++) {
free(funge[height]);
}
free(funge)
This, however gives me a double free pointer exception. Does this mean, I don't have to manage this piece of memory?. I was of the impression that, for every malloc'ed memory we should call free().
Since all the 'rows' are the same size, you can just allocate it in one swoop, with malloc(height * width * sizeof (char *)) (it's not entirely clear whether you're creating a 2d array of char or a 2d array of char *). You can use multiplication to calculate the appropriate index (i.e. foo[i][j] becomes foo + i * height + j),
free()ing it will similarly, take a single call.
In the for loop for allocation you are using i <= height; instead of i < height;. So you are writing to an invalid memory location and the behavior of your code becomes unpredictable.
The second allocation should be:
foo[i] = (char *) malloc (width * sizeof(char));
you're also looping height+1 times while allocating.
Besides that, those two snippets seem right to me, so the error should be elsewhere.
If the array was allocated as just one big chunk of memory, then you'd have to free it just once.
char **foo = (char **) malloc(height * sizeof(char *));
*foo = malloc(height * width * sizeof(char))
for (int i = 1; i < height; i++) {
foo[i] = *foo + i*width;
}
//and you just do 2 frees
free(*foo);
free(foo);
The mechanism to allocate is OK (though you should use sizeof(char) instead of sizeof(char *) in the allocate loop; you are overallocating the character strings) given that width and height are runtime values.
Your impression that you should call free() once for each malloc() is basically correct (things like calloc() and realloc() complicate the simple story).
The loop followed by free should be correct (or, at least, the general mechanism of 'free the sub-arrays first, then the array of pointers to sub-arrays) - so you need to review where the double free error is coming from. We can't see where the ip_ptr->funge_height was controlled; it is not immediately obvious that funge is described by ip_ptr->funge_height.
See the answer from 'unknown # google' - there's an array bounds problem.
When you allocate the memory, it should be i < height as the loop condition.
When you deallocate the memory, you should iterate up to the same index as you did when allocating. ip_ptr->funge_height should be the same as the original height, but it's not obviously so.
Other than that, it should work.
Here's another way, that involves fewer mallocs and frees.
To allocate:
char **foo = malloc (height * sizeof (char **));
foo[0] = malloc (height * width * sizeof (char *));
for (i = 1; i < height; ++i) {
foo[i] = foo[i-1] + width;
}
To deallocate:
free (foo[0]);
free (foo);
Allocation (assuming height > 0 and width > 0)
char **foo, *row;
assert(height > 0 && width > 0);
foo = malloc(height * sizeof *foo);
row = malloc(height * width * sizeof *row);
assert(foo != NULL && row != NULL);
for (i = 0; i < height; ++i, row += width)
foo[i] = row;
assert(row == *foo + height * width);
Deallocation
assert(foo != NULL);
free(*foo);
free(foo);
In such cases you can always use valgrind. Just compile your executable and run it:
valgrind --leak-check=full ./a.out
Valgrind will find all your memory validations and point to the code lines involved.
In your case it may have find the indexing problem (< vs. <=) easily.
If your compiler supports it, you could use a pointer to a variable-length array, ie
size_t width = 10, height = 5;
char *(*foo)[height][width] = malloc(sizeof *foo);
Keep in mind that you'll have to derefence the pointer before accessing the array elements, eg
(*foo)[1][2] = "foo";
This has the benefit that you'll only allocate a single, continuous block of memory which can be deallocated with a single call fo free().
This 100% works without exe crash.
char **map2d;
map2d=(char **)malloc(MAXY*sizeof(char *));
for(int a=0; a<MAXY; a++)
map2d[a]=(char *)malloc(MAXX*sizeof(char));
for(int a=0; a<MAXX; a++)
free(map2d[a]);
free(map2d);

Resources