web-dev-qa-db-fra.com

Comment obtenir la mémoire disponible C ++ / g ++?

Je souhaite allouer mes tampons en fonction de la mémoire disponible. Tels que, lorsque je fais du traitement et que l'utilisation de la mémoire augmente, mais reste dans les limites de mémoire disponibles. Existe-t-il un moyen d'obtenir de la mémoire disponible (je ne sais pas si l'état de la mémoire virtuelle ou physique fera une différence?). La méthode doit être indépendante de la plate-forme car elle sera utilisée sur Windows, OS X, Linux et AIX. (Et si possible, je voudrais également allouer une partie de la mémoire disponible pour mon application, quelqu'un qu'elle ne change pas pendant l'exécution).

Edit: je l'ai fait avec l'allocation de mémoire configurable. Je comprends que ce n'est pas une bonne idée, car la plupart des systèmes d'exploitation gèrent la mémoire pour nous, mais mon application était un cadre ETL (destiné à être utilisé sur le serveur, mais était également utilisé sur le bureau comme plugin pour Adobe indesign). Donc, je rencontrais un problème car au lieu d'utiliser swap, Windows retournerait une mauvaise allocation et d'autres applications commenceraient à échouer. Et comme on m'a appris à éviter les accidents et ainsi, j'essayais simplement de me dégrader gracieusement.

61
theCakeCoder

Après avoir lu ces réponses, je suis étonné que tant de gens considèrent que la mémoire informatique d'OP appartient à d'autres. C'est son ordinateur et sa mémoire à utiliser comme bon lui semble, même si cela casse d'autres systèmes en le réclamant. C'est une question intéressante. Sur un système plus primitif, j'avais memavail() qui me disait cela. Pourquoi l'OP ne prendrait-il pas autant de mémoire qu'il le souhaite sans perturber les autres systèmes?

Voici une solution qui alloue moins de la moitié de la mémoire disponible, juste pour être gentil. La sortie était:

Obligatoire FFFFFFFF

Requis 7FFFFFFF

Obligatoire 3FFFFFFF

Taille de mémoire allouée = 1FFFFFFF

#include <stdio.h>
#include <stdlib.h>

#define MINREQ      0xFFF   // arbitrary minimum

int main(void)
{
    unsigned int required = (unsigned int)-1; // adapt to native uint
    char *mem = NULL; 
    while (mem == NULL) {
        printf ("Required %X\n", required);
        mem = malloc (required);
        if ((required >>= 1) < MINREQ) {
            if (mem) free (mem);
            printf ("Cannot allocate enough memory\n");
            return (1);
        }
    }

    free (mem);
    mem = malloc (required);
    if (mem == NULL) {
        printf ("Cannot enough allocate memory\n");
        return (1);
    }
    printf ("Memory size allocated = %X\n", required);
    free (mem);
    return 0;
}
13
Weather Vane

Sur les systèmes d'exploitation de type UNIX, il y a sysconf .

#include <unistd.h>

unsigned long long getTotalSystemMemory()
{
    long pages = sysconf(_SC_PHYS_PAGES);
    long page_size = sysconf(_SC_PAGE_SIZE);
    return pages * page_size;
}

Sous Windows, il y a GlobalMemoryStatusEx :

#include <windows.h>

unsigned long long getTotalSystemMemory()
{
    MEMORYSTATUSEX status;
    status.dwLength = sizeof(status);
    GlobalMemoryStatusEx(&status);
    return status.ullTotalPhys;
}

Alors faites juste un peu de fantaisie #ifdefs et vous serez prêt à partir.

140
Travis Gockel

Il y a des raisons de vouloir le faire dans HPC pour les logiciels scientifiques. (Pas de jeu, Web, entreprise ou logiciel intégré). Les logiciels scientifiques parcourent régulièrement des téraoctets de données pour effectuer un calcul (ou une exécution) (et s'exécuter pendant des heures ou des semaines) - qui ne peuvent pas tous être stockés en mémoire (et si un jour vous me dites qu'un téraoctet est standard pour n'importe quel PC ou une tablette ou un téléphone, il est probable que le logiciel scientifique puisse gérer des pétaoctets ou plus). La quantité de mémoire peut également dicter le type de méthode/algorithme qui a du sens. L'utilisateur ne veut pas toujours décider de la mémoire et de la méthode - il/elle a d'autres choses à se soucier. Le programmeur doit donc avoir une bonne idée de ce qui est disponible (4 Go ou 8 Go ou 64 Go ou environ de nos jours) pour décider si une méthode fonctionnera automatiquement ou si une méthode plus laborieuse doit être choisie. Le disque est utilisé mais la mémoire est préférable. Et les utilisateurs de ces logiciels ne sont pas encouragés à faire trop de choses sur leur ordinateur lorsqu'ils exécutent de tels logiciels - en fait, ils utilisent souvent des machines/serveurs dédiés.

29
Paresh M

Il n'y a pas de moyen indépendant de la plateforme pour ce faire, différents systèmes d'exploitation utilisent différentes stratégies de gestion de la mémoire.

Ces autres questions de débordement de pile aideront:

Attention cependant: il est notoirement difficile d'obtenir une "vraie" valeur pour la mémoire disponible sous Linux. Ce que le système d'exploitation affiche tel qu'utilisé par un processus ne garantit pas ce qui est réellement alloué au processus.

C'est un problème courant lors du développement de systèmes Linux embarqués tels que des routeurs, où vous souhaitez mettre en mémoire tampon autant que le matériel le permet. Voici un lien vers un exemple montrant comment obtenir ces informations dans un linux (en C):

11
mikelong

Exemple Mac OS X utilisant sysctl (man 3 sysctl):

#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/sysctl.h>

int main(void)
{
    int mib[2] = { CTL_HW, HW_MEMSIZE };
    u_int namelen = sizeof(mib) / sizeof(mib[0]);
    uint64_t size;
    size_t len = sizeof(size);

    if (sysctl(mib, namelen, &size, &len, NULL, 0) < 0)
    {
        perror("sysctl");
    }
    else
    {
        printf("HW.HW_MEMSIZE = %llu bytes\n", size);
    }
    return 0;
}

(peut également fonctionner sur d'autres systèmes d'exploitation de type BSD?)

5
Paul R

Le code ci-dessous donne la mémoire totale et libre en mégaoctets. Fonctionne pour FreeBSD, mais vous devriez pouvoir utiliser les mêmes paramètres sysctl/similaires sur votre plate-forme et faire la même chose (Linux et OS X ont au moins sysctl)

#include <stdio.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>

int main(){
    int rc;
    u_int page_size;
    struct vmtotal vmt;
    size_t vmt_size, uint_size; 

    vmt_size = sizeof(vmt);
    uint_size = sizeof(page_size);

    rc = sysctlbyname("vm.vmtotal", &vmt, &vmt_size, NULL, 0);
    if (rc < 0){
       perror("sysctlbyname");
       return 1;
    }

    rc = sysctlbyname("vm.stats.vm.v_page_size", &page_size, &uint_size, NULL, 0);
    if (rc < 0){
       perror("sysctlbyname");
       return 1;
    }

    printf("Free memory       : %ld\n", vmt.t_free * (u_int64_t)page_size);
    printf("Available memory  : %ld\n", vmt.t_avm * (u_int64_t)page_size);

    return 0;
}

Voici la sortie du programme, comparée à la sortie vmstat (8) sur mon système.

~/code/memstats % cc memstats.c 
~/code/memstats % ./a.out 
Free memory       : 5481914368
Available memory  : 8473378816
~/code/memstats % vmstat 
 procs      memory      page                    disks     faults         cpu
 r b w     avm    fre   flt  re  pi  po    fr  sr ad0 ad1   in   sy   cs us sy id
 0 0 0   8093M  5228M   287   0   1   0   304 133   0   0  112 9597 1652  2  1 97
3
fnisi

La fonction "officielle" de cette est était std::get_temporary_buffer(). Cependant, vous voudrez peut-être tester si votre plate-forme a une implémentation décente. Je comprends que toutes les plateformes ne se comportent pas comme souhaité.

3
MSalters

Au lieu d'essayer de deviner, avez-vous envisagé de laisser l'utilisateur configurer la quantité de mémoire à utiliser pour les tampons, ainsi que de supposer des valeurs par défaut quelque peu conservatrices? De cette façon, vous pouvez toujours exécuter (peut-être légèrement plus lentement) sans remplacement, mais si l'utilisateur sait qu'il y a de la mémoire X disponible pour l'application, il peut améliorer les performances en configurant cette quantité.

1
Mark B