I am experimenting with memory leaks. When I run the following program from zsh, it starts and is terminated after a while. Is zsh doing it? Who decides when to kill it?
#include <iostream>
#include <stdlib.h>
int main() {
int *a = (int *) malloc(sizeof(int));
*a = 5;
std::cout << *a << std::endl;
for(int i = 0; i < 10000000000000000; ++i) {
int *c = (int *) malloc(1024); // 1kb per iteration
*c = 5;
std::cout << *c << std::endl;
}
}
It depends on how you run it, but usually it is the operating system which kills your process after malloc returns NULL (if unable to allocate new memory) and you attempt to write a value (5) to that address. So basically it's a NULL pointer dereference where your code attempts to access memory at address NULL.
Philosophically speaking, it is the programmer who decided to write faulty code and crash his program. :-)
EDIT: On the other hand, it might still be the fault of the OS (or its programmers) if it attempts to overcommit memory to your process. For example, by default memory overcommit is enabled in Linux. This means that even when the OS has no memory available, it lies to the process by letting memory allocation methods to succeed and actually tries to allocate the memory when first accessed by the process. This might lead to cases where malloc succeeds and returns a non-NULL value, and later when the process attempts to access that memory the OS will try to allocate it. If OS fails, then it either has to block/pause the process or kill it. Linux usually runs its infamous OOM-killer which selects processes to kill when memory allocation fails. And very often the process to kill is the one allocating a lot of memory, your process.
Related
#include <iostream>
int main(int argc, char** argv) {
int* heap_var = new int[1];
/*
* Page size 4KB == 4*1024 == 4096
*/
heap_var[1025] = 1;
std::cout << heap_var[1025] << std::endl;
return 0;
}
// Output: 1
In the above code, I allocated 4 bytes of space in the heap. Now as the OS maps the virtual memory to system memory in pages (which are 4KB each), A block of 4KB in my virtual mems heap would get mapped to the system mem. For testing I decided I would try to access other addresses in my allocated page/heap-block and it worked, however I shouldn't have been allowed to access more than 4096 bytes from the start (which means index 1025 as an int variable is 4 bytes).
I'm confused why I am able to access 4*1025 bytes (More than the size of the page that has been allocated) from the start of the heap block and not get a seg fault.
Thanks.
The platform allocator likely allocated far more than the page size is since it is planning to use that memory "bucket" for other allocation or is likely keeping some internal state there, it is likely that in release builds there is far more than just a page sized virtual memory chunk there. You also don't know where within that particular page the memory has been allocated (you can find out by masking some bits) and without mentioning the platform/arch (I'm assuming x86_64) there is no telling that this page is even 4kb, it could be a 2MB "huge" page or anything alike.
But by accessing outside array bounds you're triggering undefined behavior like crashes in case of reads or data corruption in case of writes.
Don't use memory that you don't own.
I should also mention that this is likely unrelated to C++ since the new[] operator usually just invokes malloc/calloc behind the scenes in the core platform library (be that libSystem on OSX or glibc or musl or whatever else on Linux, or even an intercepting allocator). The segfaults you experience are usually from guard pages around heap blocks or in absence of guard pages there simply using unmapped memory.
NB: Don't try this at home: There are cases where you may intentionally trigger what would be considered undefined behavior in general, but on that specific platform you may know exactly what's there (a good example is abusing pthread_t opaque on Linux to get tid without an overhead of an extra syscall, but you have to make sure you're using the right libc, the right build type of that libc, the right version of that libc, the right compiler that it was built with etc).
I'm developing on OS X 10.8.3. The following code is simple. It can perform two operations. If the read function is uncommented then the program will open the file at "address" and transfer all of its contents into data. If instead, the memcpy function is uncommented the program will copy the mmapped contents into data. I am developing on a mac which caches commonly used files in inactive memory of RAM for faster future access. I have turned off caching in both the file control and mmap becuase I am working with large files of 1 GB or greater. If i did not setup the NOCACHE option, the entire 1 GB would be stored in inactive memory.
If the read function is uncommented, the program behaves as expected. Nothing is cached and everytime the program is ran it takes about 20 seconds to read the entire 1 GB.
But if instead the memcpy function is uncommented something changes. Still i see no increase in memory and it still takes 20 seconds to copy on the first run. But every execution after the previous one, copies in under a second. This is very analogous to the behavior of caching the entire file in inactive memory, but I never see an increase in memory. Even if I then do not mmap the file and only perform a read, it performs in the same time, under a second.
Something must be getting stored in inactive memory, but what and how do I track it? I would like to find what is being stored and use it to my advantage.
I am using activity monitor to see a general memory size. I am using Xcode Instruments to compare the initial memcpy execution to an execution where both read and memcpy are commented. I see no difference in the Allocations, File Activity, Reads/Writes, VM Tracker, or Shared Memory tools.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main(int argc, const char * argv[])
{
unsigned char *data;
unsigned char *mmapdata;
size_t length;
int file = open("address", O_RDONLY);
fcntl(file, F_NOCACHE, 1);
struct stat st;
stat("address", &st);
length = st.st_size;
data = malloc(length);
memset(data,0,length);
mmapdata = mmap(NULL, length, PROT_READ,MAP_SHARED|MAP_NOCACHE, file, 0);
if (mmapdata == MAP_FAILED)
fprintf(stderr, "failure");
// read(file,data,length);
close(file);
// memcpy(data,mmapdata,length);
munmap(mmapdata,length);
free(data);
return 0;
}
UPDATE:
Sorry if I was unclear. During program execution, the active memory portion of my RAM increases according to the data I malloc and the size of the mmapped file. This is surely where the pages are residing. After cleanup, the amount of available memory returns to as it was before. Inactive memory is never increased. It makes sense that the OS wouldn't really throw that active memory away since free memory is useless, but this process is not identical to caching, because of the following reason. I've tested two scenarios. In both I load a number of files who's size totals more than my available ram. One scenario I cache the files and one I do not. With caching, my inactive memory increases and once I fill my ram everything slows down tremendously. Loading a new file will replace another file's allocated inactive memory but this process will take an exceptionally longer time than the next scenario. The next scenario is with caching off. I again run the program several times loading enough files to fill my ram, but inactive memory never increases and active memory always returns to normal so it appears I've done nothing. The files I've mmapped still load fast, just as before, but mmapping new files load in a normal amount of time, replacing other files. My system never slows down with this method. Why is the second scenario faster?
How could the OS possibly make a memcpy on an mmap'd file work if the file's pages weren't resident in memory? The OS takes your hint that you don't want the data cached, but if still will if it has no choice or it has nothing better to do with the memory.
Your pages have the lowest priority, because the OS believes you that you won't access them again. But they had to be resident for the memcpy to work, and the OS won't throw them away just to have free memory (which is 100% useless). Inactive memory is better than free memory because there's at least some chance it might save I/O operations.
Quick curious question, memory allocation addresses are choosed by the language compiler or is it the OS which chooses the addresses for the memory asked?
This is from a doubt about virtual memory, where it could be quickly explained as "let the process think he owns all the memory", but what happens on 64 bits architectures where only 48 bits are used for memory addresses if the process wants a higher address?
Lets say you do a int a = malloc(sizeof(int)); and you have no memory left from the previous system call so you need to ask the OS for more memory, is the compiler the one who determines the memory address to allocate this variable, or does it just ask the OS for memory and it allocates it on the address returned by it?
It would not be the compiler, especially since this is dynamic memory allocation. Compilation is done well before you actually execute your program.
Memory reservation for static variables happens at compile time. But the static memory allocation will happen at start-up, before the user defined Main.
Static variables can be given space in the executable file itself, this would then be memory mapped into the process address space. This is only one of few times(?) I can image the compiler actually "deciding" on an address.
During dynamic memory allocation your program would ask the OS for some memory and it is the OS that returns a memory address. This address is then stored in a pointer for example.
The dynamic memory allocation in C/C++ is simply done by runtime library functions. Those functions can do pretty much as they please as long as their behavior is standards-compliant. A trivial implementation of compliant but useless malloc() looks like this:
void * malloc(size_t size) {
return NULL;
}
The requirements are fairly relaxed -- the pointer has to be suitably aligned and the pointers must be unique unless they've been previously free()d. You could have a rather silly but somewhat portable and absolutely not thread-safe memory allocator done the way below. There, the addresses come from a pool that was decided upon by the compiler.
#include "stdint.h"
// 1/4 of available address space, but at most 2^30.
#define HEAPSIZE (1UL << ( ((sizeof(void*)>4) ? 4 : sizeof(void*)) * 2 ))
// A pseudo-portable alignment size for pointerĊbwitary types. Breaks
// when faced with SIMD data types.
#define ALIGNMENT (sizeof(intptr_t) > sizeof(double) ? sizeof(intptr_t) : siE 1Azeof(double))
void * malloc(size_t size)
{
static char buffer[HEAPSIZE];
static char * next = NULL;
void * result;
if (next == NULL) {
uintptr_t ptr = (uintptr_t)buffer;
ptr += ptr % ALIGNMENT;
next = (char*)ptr;
}
if (size == 0) return NULL;
if (next-buffer > HEAPSIZE-size) return NULL;
result = next;
next += size;
next += size % ALIGNMENT;
return result;
}
void free(void * ptr)
{}
Practical memory allocators don't depend upon such static memory pools, but rather call the OS to provide them with newly mapped memory.
The proper way of thinking about it is: you don't know what particular pointer you are going to get from malloc(). You can only know that it's unique and points to properly aligned memory if you've called malloc() with a non-zero argument. That's all.
Suppose I have some code that looks like this:
#include "mpi.h"
int main( int argc, char** argv )
{
int my_array[10];
//fill the array with some data
MPI_Init(&argc, &argv);
// Some code here
MPI_Finalize();
return 0;
}
Will each MPI instance get its own copy of my_array? Only rank 0? None of them? Is it bad practice to have any code before MPI_Init at all?
The short answer to "what happens to memory when I call MPI_Init" is: nothing.
MPI_Init initializes the MPI library in the calling process. Nothing more, nothing less. At the time of the MPI_Init call, all the MPI processes already exist, they just don't know about each other yet and can't communicate.
Each MPI process is a separately executing program. The processes do not share memory, and communicate by passing messages.
Indeed, the processes calling MPI_Init can even be different programs entirely, as long as the messages they pass around match. This is the MPMD model.
When you run mpi code, you are running the same code in different process (they can not share memory), so each process will have his own array.
The arrays should be equal, unless your data depend of time (the process are not necessarily synchronized), process rank (I think the rank is only available after the init call) or any random number generators (some may generate random seeds as well).
I have two questions:
Q1. The character pointers are used to point to a location where a given string is stored. If we keep reassigning the string, does it lead to memory leak?
On a Linux system I see:
$ cat chk.c
#include <stdio.h>
#define VP (void *)
int main()
{
char *str;
str = "ABC";
printf("str = %p points to %s\n", VP str, str);
str = "CBA";
printf("str = %p points to %s\n", VP str, str);
return 0;
}
$ cc chk.c && ./a.out
str = 0x8048490 points to ABC
str = 0x80484ab points to CBA
$
Q2. What is the maximum length of a string that can be assigned as above?
Can your sample code memory leak?
No.
You are assigning constant strings already in your program so no extra memory allocation happens.
Memory leaks are from forgotten malloc() type calls, or calls that internally do mallocs() type operations that you may not be aware of. Beware of functions that return a pointer to memory... such as strdup(). Such tend to either be not be thread safe or leak memory, if not both. Better are functions like snprintf() where the caller provides both a memory buffer and a maximum size. These function's don't leak.
Maximum string length: tends to have no artificial limit except available memory. Memory in the stack may be limited by various constraints (char can_be_too_big[1_000_000]), but memory from malloc() is not. Malloc memory ias a question of how much free memory you have (char * ok = malloc(1_000_000). Your local size_t provides the maximum memory to allocate in theory, but in practice it is much smaller.
Memory leaks only prevail when we allocate memory using malloc/realloc/calloc and forget to free it. In the above example, no where the we are allocating memory our self, so no memory leaks AFAIK.
OK, to be more specific, usually what happens (OS-specific, but AFAIK, this is universal, possibly in a spec somewhere) is that somewhere in the instruction set of your executable are the strings "ABC" and "CBA" - these are embedded in your program itself. When you do str="ABC" you are saying, "I want this string pointer to point to the address in my compiled program that contains the string ABC". This is why there is a difference between "strings" at runtime and "string literals" if you see that in documentation anywhere. Since you didn't allocate space for your literal - the compiler baked it into your program - you don't have to deallocate space for it.
Anyway, when your process gets unloaded the OS frees up this resource as a natural side effect of unloading your program. In fact, in general, it is impossible to leak after a program exits because the OS will deallocate any resources you forget to, even heinous leaks, on program exit. (this is not entirely true - you can cause another program, which is not unloaded, to leak if you do linked library stuff - but it's close enough). It's just one of those things that the OS takes care of.
when you Allocate Memory for somePointer p,and without freeing the memory or without making the other pointers to point to that memory,if you change the value of p,then in this situvation memory leak occurs.
(E.g)
char* p = malloc(sizeof(char)*n);
char* q= "ABC";
Then if you assign,
p=q;
Then there will be a memory leak.
If you dont use memory allocation,Then there wont be any memory leak.
And,
char* q= "ABC";
In this statement q will be automatiacally points to a constant location. Hence q value cannot be modified.
(E.g)
char* q = "ABC";
q[1] = 'b';
These statements will result in segmentation Fault.
MoreReference:
ErrorOnModifyingValue
DynamicMemoryAllocation