I'm trying to learn about memory and page fault, so I wrote the code below to check my understanding. I don't understand why calling malloc caused MINFL to increase since malloc() shouldn't affect physical memory (from what I understand).
This is my code:
#include <stdio.h>
#include <stdlib.h>
void main() {
printf("Before malloc\n");
getchar();
malloc(1 << 20);
printf("After malloc\n");
getchar();
}
These are the terminal results of ps command.
Before malloc:
After malloc:
There are 2 things I don't understand:
why does MINFL increase?
why does VSZ increase by 1028 and not 1024?
Please help and Thank you.
The answer to both of them is the same and very simple indeed.
As you might know, Glibc malloc will use mmap to directly allocate a block larger than 128 KiB. However, it will need to write bookkeeping information below the pointer - because how else would free know what it should be done when just given a pointer. If you print the pointer that malloc returned, you'll see that it is not page aligned.
Here's a program that demonstrates all this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
#define ALLOCATION_SIZE (1 << 20)
int main(void) {
struct rusage usage = {0};
getrusage(RUSAGE_SELF, &usage);
printf("1st before malloc: %lu\n", usage.ru_minflt);
getrusage(RUSAGE_SELF, &usage);
printf("2nd before malloc: %lu\n", usage.ru_minflt);
char *p = malloc(ALLOCATION_SIZE);
printf("pointer returned from malloc: %p\n", p);
getrusage(RUSAGE_SELF, &usage);
printf("after malloc: %lu\n", usage.ru_minflt);
p[0] = 42;
getrusage(RUSAGE_SELF, &usage);
printf("after writing to the beginning of the allocation: %lu\n", usage.ru_minflt);
for (size_t i = 0; i < ALLOCATION_SIZE; i++) {
p[i] = 42;
}
getrusage(RUSAGE_SELF, &usage);
printf("after writing to every byte of the allocation: %lu\n", usage.ru_minflt);
}
outputs something like
1st before malloc: 108
2nd before malloc: 118
pointer returned from malloc: 0x7fbcb32aa010
after malloc: 119
after writing to the beginning of the allocation: 119
after writing to every byte of the allocation: 375
i.e. getrusage and printf cause page faults the first time around, so we call it twice - now the fault count is 118 before the malloc call, and after malloc it is 119. If you look at the pointer, 0x010 is not 0x000 i.e. the allocation is not page-aligned - those first 16 bytes contain bookkeeping information for free so that it knows that it needs to use munmap to release the memory block, and the size of the allocated block!
Now naturally this explains why the size increase was 1028 Ki instead of 1024 Ki - one extra page had to be reserved so that there would be enough space for those 16 bytes! It also explains the source of the page fault - because malloc had to write the bookkeeping information to the copy-on-write zeroed page. This can be proved by writing to the first byte of the allocation - it doesn't cause a page fault any longer.
Finally the for loop will modify the pages and touch the remaining 256 pages out of those 257 mapped in.
And if you change ALLOCATION_SIZE to ((1 << 20) - 16) i.e. allocate just 16 bytes less, you'd see that the both virtual size and the number of page faults would match the values you were expecting.
Related
P.S.: I have almost all questions for "invalid next size" but they are not helping me because I do not have another piece of code which malloc or realloc, so that is ruled out. Also, I am not assigning beyond the limits of memory space so I am fine on that front as well.
I have below code which is giving me - *** Error in./server_issue': realloc(): invalid next size: 0x08249170 ***`.
I am not able to identify the problem, I am allocating just 64 bytes at a time so I am not out of memory address space and there is other memory allocation which could have possibly corrupted my heap memory.
Error says, invalid next size but as my last log tells Reallocating 64 bytes, Aborted (core dumped) so it means I am still trying to allocate 64 bytes. So, why error?
For HTML file, have any file which is more than 256 bytes.
Code: (minimum code to reproduce the issue)
#include<stdio.h>
#include<stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef char BYTE;
bool load(FILE*, BYTE**, size_t*);
int main(void)
{
FILE* file = fopen("/home/university/psets/pset6/pset6_working/public/hello.html", "r");
BYTE* content;
size_t length;
load(file, &content, &length);
}
bool load(FILE* file, BYTE** content, size_t* length)
{
int totalLength = 0;
int readBytes = 0;
*content = NULL;
BYTE* fileContentTemp[64]; // working with 222222
while ((readBytes = fread(fileContentTemp, 1, 64, file)) > 0)
{
printf("Reallocating %d bytes, ", readBytes);
*content = realloc(*content, readBytes);
printf("%p\n", *content);
if(totalLength != 0)
{
memcpy(*content + totalLength + 1, fileContentTemp, readBytes);
} else{
memcpy(*content + totalLength, fileContentTemp, readBytes);
}
totalLength = totalLength + readBytes;
}
*length = totalLength;
printf("CC image: %s\n", *content);
printf("length is %d\n", *length);
printf("fileContent %p\n", *content);
return true;
}
Output:
Reallocating 64 bytes, 0x8249170
Reallocating 64 bytes, 0x8249170
*** Error in `./server_issue': realloc(): invalid next size: 0x08249170 ***
Reallocating 64 bytes, Aborted (core dumped)
Update:
Even if I allocate 64 bytes instead of using readBytes while realloc then also I get the same error. I am getting error because of this line - *content = realloc(*content, readBytes);
Also, I am not assigning beyond the limits of memory space so I am fine on that front as well.
Being overly sure of your code is a great way to make debugging more difficult. Suspect everything is wrong.
You're not allocating enough memory, because you're using realloc incorrectly.
p = realloc(p, n) doesn't add n bytes to the allocation, it changes the total allocation size to the size you tell it.
Each time through the loop you're passing readBytes which is the number of additional bytes you want to copy. So your buffer never grows. But then you proceed to write past the end of it:
memcpy(*content + totalLength, ...
as totalLength keeps growing throughout the loop.
Calling realloc in a loop like this is typically a bad idea performance-wise. You should allocate enough total space up-front, and then read into it in the loop.
To get the total file size:
size_t get_file_size(FILE *f)
{
long oldpos;
size_t result;
// Save the original file position
oldpos = ftell(f);
// Seek to the first byte past the end of the file
fseek(f, 0, SEEK_END);
// Get the file position - the number of bytes in the file
result = ftell(f);
// Return the file position to where it was
fseek(f, oldpos, SEEK_SET);
return result;
}
Here's a test, to demostrate what I am saying about realloc. Note, this uses malloc_usable_size which is bad practice, in general.
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main(void)
{
int i;
char *p = NULL;
for (i = 0; i < 10; i++) {
p = realloc(p, 16);
printf("[%d] size: %zd\n", i, malloc_usable_size(p));
}
return 0;
}
Output:
$ gcc -Wall -Werror -o realloc realloc.c
$ ./realloc
[0] size: 24
[1] size: 24
[2] size: 24
[3] size: 24
[4] size: 24
[5] size: 24
[6] size: 24
[7] size: 24
[8] size: 24
[9] size: 24
Note that malloc_usable_size() returns the same value, even after multiple calls to realloc which pass the same size. Also, the fact that it returns 24, even though we allocated 16 bytes is expected, and is a result of implementation details of the allocator.
From the man page for malloc_usable_size:
NOTES
The value returned by malloc_usable_size() may be greater than the requested size of the allocation because of alignment and minimum size constraints. Although the excess bytes can be overwritten by the application without ill effects, this is not good programming practice: the number of excess bytes in an allocation depends on the underlying implementation.
The main use of this function is for debugging and introspection.
I am trying to make a program that allocates memory and then fill the allocated memory with random data, in this case A and does this a number of times and then print the time it takes to fill 100 mb in milli seconds.
The program is supposed to allocate a multiple of 100 mb each time. The program is supposed to do this up to 9000 mb. The reason I do this is to demonstrate how the OS behaves when it runs out of free memory and use swap space. However I have issues doing this.
When I run the program it behaves like it's supposed to do until I reach 2100 mb then it stop allocating memory and after a while the error handler kicks in and quit the program because malloc() returns NULL.
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#include <unistd.h>
#define KILO 1024
#define MEGA (KILO*KILO)
#define INCREMENT 100
int diffTime(struct timeval * startTime, struct timeval * endTime) {
return ((endTime->tv_sec - startTime->tv_sec)*1000 + (endTime->tv_usec- startTime->tv_usec)/1000);
}
int createBigDatablock(long int storlek) {
char *arr = (char*) malloc(storlek*MEGA);
if (arr==NULL){
printf("Error: not allocating memory");
exit (-1);
}
for(int i = 0;i<storlek*MEGA;i++){
arr[i] = 'A';
}
fflush(stdin);
getchar();
free(arr);
return 0;
}
int main(void) {
long int i;
struct timeval startT, endT;
// struct timezone tzp;
for(i=INCREMENT;i<=9000;i=i+INCREMENT){
gettimeofday(&startT, NULL); //&tzp); /* hämta starttid */
createBigDatablock(i);
gettimeofday(&endT, NULL);//&tzp); /* hämta sluttid */
printf("Datablock %ld MB took %d msec\n",i, diffTime(&startT,&endT));
}
return 0;
}
I have tried to run this on a virtual machine with debian 8 with 4 gb memory and 570 mb swap. The memory is never completely filled and the swap space is never touched. If someone can help me figure this out I will be greatful
You probably have a 32bit system where you cannot allocate more than 2 gigabytes of memory per process.
If malloc returns NULL, that means that it couldn't allocate memory.
So the behaviour of your program is normal.
Another possibility is that it simply cannot find a large enough free contiguous memory block.
The reason why the swap space is never touched may be because there is always enough free memory available because your virtual machine has 4gb of memory.
If you want to use the swap space, you could try to allocate lots of smaller chunks of memory, for example 40 times 100Mb; then the overall quantity of memorty you are able to allocate may also be higher than 2100Mb.
I stumbled on this code and compiled it on a Fedora 34 X86_64 system. It would segfault at Datablock 2100 on the loop that writes an A to a memory location. I changed the i to long int i and my system ground to almost a halt but a watched free in another terminal showed it was filling swap. I have not fully tested it but it seems to be working. There are two i variables in this and perhaps they're considered separate.
for(int i = 0;i<storlek*MEGA;i++){
arr[i] = 'A';
for(long int i = 0;i<storlek*MEGA;i++){
arr[i] = 'A';
I'm having memory leaks in a larger program and I believe this is the cause of it.
#include <stdlib.h>
#include <Windows.h>
typedef struct _struct{
char* name;
} str;
int main() {
system("PAUSE");
str* Character = (str*)malloc(sizeof(str) * 20000);
for(int i = 0; i < 20000; i++){
Character[i].name = (char*)malloc(20000); // Assign memory.
}
for(int i = 0; i < 20000; i++){
free(Character[i].name); // Free memory.
}
free(Character);
system("PAUSE");
}
Memory at first pause: ~500K.
Memory at second pause: ~1.7M.
Using VS2012 for testing. Any ideas?
How are you measuring the amount of memory occupied by the program? One thing off the top of my head is that you're looking at the size of the working set the OS is keeping track of. Since you've allocated and freed a lot of memory, the size of that set has increased. Some OSs will adjust the size of the working set after a while, some won't. What OS are we looking at here?
When you call malloc, memory is allocated on the heap. If there is insufficient space left on the heap, the program will ask the OS for more memory and another chunk is acquired. Memory acquired from the OS is usually not returned until the program finishes (although this is up to the OS).
Program size alone can not normally be used to check for memory leaks! Use Valgrind or a similar tool to check for memory that never gets freed.
str* Character = (str*)malloc(sizeof(str) * 20000);
In the above line you are allocating the memory by finding the size of the struct. Here the size of the structure you will get will be the size of the pointer width and not the size of the char.
suppose for example if the pointer width is 32 bit the it will allocate (4 * 20000) = 80000 bytes.
If you want to allocate for 20000 struct's,
str* Character = (str*)malloc(sizeof(char) * 20000);
Sorry if the title isn't as descriptive as it should be, the problem is hard to put in a few words. I am trying to find out how much mem i have available by malloc'ing and if that worked, writing to that segment. On certain systems (all linux on x86_64) i see segfaults when writing to the 2049th mib. The code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
int main (int argc, char **argv) {
void *addr;
int megasize = 2100
/// allocate the memory via mmap same result
//addr = mmap ((void *) 0, (size_t) megasize << 20, PROT_READ | PROT_WRITE,
// MAP_PRIVATE | MAP_ANONYMOUS, (int) -1, (off_t) 0);
addr = malloc(megasize << 20);
if (addr == MAP_FAILED) {
fprintf (stderr, "alloc of %d megabytes failed %s\n", megasize,
strerror (errno));
exit (1);
};
printf ("got %d megabytes at %p\n", megasize, addr);
{
int i;
char *p = addr;
printf("touching the %d Mb memory:\n", megasize);
for (i = 0; i < megasize; i++) {
p[i << 20] = 0;
putchar('.');
if (i%64==63) // commenting out this line i see that it really is the 2049th mb
printf(" #%d\n", i);
fflush(stdout);
};
putchar('\n');
};
/// free the memory
munmap (addr, (size_t) megasize << 20);
return 0;
}
It segfaults reliably on some systems, whereas on others it works fine. Reading the logs for the systems where it fails tells me it's not the oom killer. There are values for megasize that i can choose which will cause malloc to fail but those are larger.
The segfault occurs reliably for any size bigger than 2gib and smaller than the limit where malloc returns -1 for those systems.
I believe there is a limit i am hitting that isn't observed by malloc and i can't figure out what it is. I tried reading out a few of the limits via getrlimit that seemed relevant like RLIMIT_AS and RLIMIT_DATA but those were way bigger.
This is the relevant part of my valgrindlog
==29126== Warning: set address range perms: large range [0x39436000, 0xbc836000) (defined)
==29126== Invalid write of size 1
==29126== at 0x400AAD: main (in /home/max/source/scratch/memorytest)
==29126== Address 0xffffffffb9436000 is not stack'd, malloc'd or (recently) free'd
Can anybody please give me a clue as to what the problem is?
You'll be getting an overflow when counting via int i, as int is 4 bytes wide here:
p[i << 20] = ...
Change
int i;
to be
size_t i;
size_t is the preferred type when addressing memory.
An 32-bit int cannot store the value 2049 mb. You're invoking undefined behavior via signed integer overflow, and happen to be getting a negative number. On most 32-bit machines, when added to a pointer that wraps back around and ends up giving you the address you wanted, by accident. On 64-bit machines, that gives you an address roughly 2047 mb below the start of your block of memory (or wrapped around to the top of the 64-bit memory space).
Use the proper types. Here, i should have type size_t.
Why is the following code resulting in Segmentation fault? (I'm trying to create two matrices of the same size, one with static and the other with dynamic allocation)
#include <stdio.h>
#include <stdlib.h>
//Segmentation fault!
int main(){
#define X 5000
#define Y 6000
int i;
int a[X][Y];
int** b = (int**) malloc(sizeof(int*) * X);
for(i=0; i<X; i++){
b[i] = malloc (sizeof(int) * Y);
}
}
Weirdly enough, if I comment out one of the matrix definitions, the code runs fine. Like this:
#include <stdio.h>
#include <stdlib.h>
//No Segmentation fault!
int main(){
#define X 5000
#define Y 6000
int i;
//int a[X][Y];
int** b = (int**) malloc(sizeof(int*) * X);
for(i=0; i<X; i++){
b[i] = malloc (sizeof(int) * Y);
}
}
or
#include <stdio.h>
#include <stdlib.h>
//No Segmentation fault!
int main(){
#define X 5000
#define Y 6000
int i;
int a[X][Y];
//int** b = (int**) malloc(sizeof(int*) * X);
//for(i=0; i<X; i++){
// b[i] = malloc (sizeof(int) * Y);
//}
}
I'm running gcc on Linux on a 32-bit machine.
Edit: Checking if malloc() succeeds:
#include <stdio.h>
#include <stdlib.h>
//No Segmentation fault!
int main(){
#define X 5000
#define Y 6000
int i;
int a[X][Y];
int* tmp;
int** b = (int**) malloc(sizeof(int*) * X);
if(!b){
printf("Error on first malloc.\n");
}
else{
for(i=0; i<X; i++){
tmp = malloc (sizeof(int) * Y);
if(tmp)
b[i] = tmp;
else{
printf("Error on second malloc, i=%d.\n", i);
return;
}
}
}
}
Nothing is printed out when I run it (expect of course for "Segmentation fault")
Your a variable requires, on a 32-bit system, 5000 * 6000 * 4 = 120 MB of stack space. It's possible that this violates some limit, which causes the segmentation fault.
Also, it's of course possible that malloc() fails at some point, which might casue you to dereference a NULL pointer.
You are getting a segmentation fault which means that your program is attempting to access a memory address that has not been assigned to its process. The array a is a local variable and thus allocated memory from the stack. As unwind pointed out a requires 120 Mbytes of storage. This is almost certainly larger than the stack space that the OS has allocated to your process. As soon as the for loop walks off the end of the stack you get a segmentation fault.
In Linux the stack size is controlled by the OS not the compiler so try the following:-
$ ulimit -a
In the response you should see a line something like this:-
stack size (kbytes) (-s) 10240
This means that each process gets 10Mbyte of storage, nowhere near enough for your large array.
You can adjust the stack size with a ulimit -s <stack size> command but I suspect it will not allow you to select a 120Mbyte stack size!
The simplest solution is to make a a global variable instead of an local variable.
Try to increase heap and stack limits in GCC:
gcc -Wl,--stack=xxxxx -Wl,--heap=yyyyy
Those are sizable allocations. Have you tried checking to make sure malloc() succeeds?
You might use malloc() for all your arrays, and check to make sure it succeeds each time.
A stack overflow (how appropriate!) can result in a segmentation fault which is what it seems you're seeing here.
In your third case the stack pointer is being moved to an invalid address but isn't being used for anything since the program then exits. If you put any operation after the stack allocation you should get a segfault.
Perhaps the compiler is just changing the stack pointer to some large value but never using it, and thus never causing a memory access violation.
Try initializing all of the elements of A in your third example? Your first example tries to allocate B after A on the stack, and accessing the stack that high (on the first assignment to B) might be what's causing the segfault.
Your 3rd code doesn't work either (on my system at least).
Try allocating memory to array a on the heap rather(when dimensions are large).
Both matrices don't fit in the limits of your memory. You can allocate only one at a time.
If you define Y as 3000 instead of 6000, your program should not issue segfault.