Initial questions
I will answer you with the information provided in the comments waiting for you to modify the question based on them.
Can a C variable be stored on the hard drive instead of RAM?
The variables are ALWAYS stored in the computer's memory and it is not possible to do what you ask as you put it.
Now, based on the additional data you provide in the comments, it is possible to map the contents of a file in memory. The operating system will manage the page changes between memory and the file in a transparent way to the programmer.
how can you get a reading of the memory used in real time, so that a program will abort automatically if it takes too much?
The programming language C does not provide mechanisms to check the memory usage of an application.
Now, based on the additional data provided in the comments, you have two possible solutions.
Specific responses
Taking into account the nature of your code (you want to use a memory area that grows over time) and the platform on which you run it (Ubuntu), the solutions that I propose (along with a slight modification to the questions so that they are more in line with your problem) are the following:
Can the contents of a file be mapped in C to be used in my application as if it were part of the memory?
Yes. Virtually all current operating systems support mapping of files in memory. It is a technique similar to virtual memory, in which the operating system manages page faults to bring areas of the file to memory and dump them back to the file with each change transparently.
On POSIX operating systems use mmap
:
Since mmapped pages can be stored back to their file when physical memory is low, it is possible to mmap files orders of magnitude larger than both the physical memory and swap space. The only limit is address space.
The translation:
Since memory-mapped pages can be stored back in your file when physical memory is low, it is possible to map into memory files orders of magnitude greater than physical memory and exchange memory together. The only limit is the address space.
On Windows you can check: link
A very simple example of using mmap
is in the next gist :
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
int main(int argc, char** argv) {
double *datos;
int fd;
size_t filesize;
/* Si no indicamos el archivo a usar, fallamos la ejecución */
if (argc != 2) {
fprintf(stderr, "Uso: %s <archivo>\n", argv[0]);
return 1;
}
/* Tratamos de crear el archivo nuevo */
fd = open(argv[1], O_RDWR | O_CREAT | O_EXCL, S_IRWXU);
/* Si falla la creación tratamos de abrirlo */
if (fd == -1) {
struct stat st;
/* Abrimos el archivo previo */
fd = open(argv[1], O_RDWR);
assert(fd != -1);
}
/* Reservamos la memoria que deseemos, es el equivalente al "malloc" */
filesize = 12000 * sizeof(double);
/* Creamos el archivo al tamaño deseado */
ftruncate(fd, filesize);
/* Mapeamos el contenido del archivo en memoria */
datos = (double *)mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, 0);
assert(datos != MAP_FAILED);
/* Leemos el valor inicial y lo modificamos */
printf("Datos iniciales: %lf\n", datos[0]);
datos[0] = 3.141592;
/* Desmapeamos el archivo de la memoria */
int rc = munmap(datos, filesize);
assert(rc == 0);
/* Cerramos el archivo */
close(fd);
}
An example of operation:
$ ./ejemplo /tmp/ejemplo
Datos iniciales: 0.000000
$ ./ejemplo /tmp/ejemplo
Datos iniciales: 3.141592
$ ls -ltrh /tmp/ejemplo
-rwx------ 1 ... 94K ... /tmp/ejemplo
$ du -hs /tmp/ejemplo
4,0K /tmp/ejemplo
Where you can see that use is made of scattered files (sparse files) to store the information. Only memory areas with values different from 0
s occupy disk space. In this example we use 4K on disk (the minimum size of a file) even if it shows 94K as the size of it.
That code will not work in Windows, so I've given you a portable example using boost
in the this gist .
How could you limit the use of memory or get the use to control it or else?
On POSIX operating systems you have getrusage()
available (see example below).
But, even more interesting, your operating system allows you to limit the resources used through the system's shell tool ulimit
or through the function C setrlimit()
.
Using limit
we could limit the memory usage of what we execute from this moment on that console (if we change to another it will not have been altered and if we create a new one the limit will be restored) as follows:
$ ulimit -v $((100*1024))
In this way we will limit the use to 100 MB of memory from that moment onwards (until closing that terminal and only what is executed inside it).
Through setrlimit
you will need to assign RLIMIT_AS
:
#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdlib.h>
int main(int argc, char** argv) {
void *mem1, *mem2;
struct rusage uso;
struct rlimit limite;
/* Limitamos la memoria a 100 MB */
limite.rlim_cur = limite.rlim_max = 100 * 1024 * 1024;
setrlimit (RLIMIT_AS, &limite);
/* Pedir 10 KB será posible */
mem1 = malloc(10 * 1024);
printf("Memoria 1: %p\n", mem1);
/* Pedir 100 MB adicionales ya no será posible */
mem2 = malloc(100 * 1024 * 1024);
printf("Memoria 2: %p\n", mem2);
/* Mostrará el uso de memoria (sólo la primera reserva más pila) */
getrusage(RUSAGE_SELF, &uso);
printf("Uso de memoria: %ld KB\n", (long)uso.ru_maxrss);
}
The result of the execution would be:
$ ./ejemplo
Memoria 1: 0x899010
Memoria 2: (nil)
Uso de memoria: 4988 KB
The second memory request failed due to exceeding the imposed limits.
The content of ru_maxrss
is in KB:
ru_maxrss
This is the maximum resident set size used (in kilobytes).