2010-02-06 4 views
2

Nous avons récemment reçu un rapport indiquant que notre application ne fonctionnera pas de temps en temps. Je traqué le code de problème à ceci:Modifiez la stratégie malloc pour le tableau 2D afin que malloc réussisse

struct ARRAY2D 
{ 
    long[] col; 
} 

int numRows = 800000; 
int numCols = 300; 
array = (ARRAY2D*) malloc(numRows * numCols * sizeof(long)) 

Cette allocation de 800 Mo peut échouer si l'utilisateur ne dispose pas d'un grand bloc assez libre. Quelle est la meilleure façon de changer la façon dont j'alloue la mémoire?

Gardez à l'esprit que j'ai une grande quantité de code qui accède à cet objet comme celui-ci: array [suite] .col [colNum], donc je besoin de quelque chose qui nécessite mineur ou trouver principalement & remplacer édition du tableau code d'accès.

+2

Utilisez-vous C ou C++? Vos tags n'aident pas. –

+0

@Poita: il utilise probablement le C++ mais seulement les fonctionnalités C. * hausser * –

+0

Est-il toujours le cas que votre application doit allouer cette mémoire ou est-elle dépendante d'un scénario particulier dans l'application? – zebrabox

Répondre

6

Vous pouvez allouer des blocs de mémoire plus petits séparément, au lieu d'un seul bloc.

long** array = NULL; 
array = (long**) malloc(numCols * sizeof(long*)); 
for (int i = 0; i < numCols; i++) 
    array[i] = (long*) malloc(numRows * sizeof(long)); 

Généralement, memory allocation may fail, chaque allocation. Cependant, disons statistiquement, en raison de memory fragmentation, l'allocation d'un seul grand bloc de mémoire a plus de chance d'échouer plus souvent que d'allouer N nombre de blocs plus petits. Cependant, la solution ci-dessus peut aussi poser des problèmes car elle est un peu comme une épée à double lame car elle peut entraîner une fragmentation de la mémoire. En d'autres termes, il n'y a pas de réponse généralement parfaite et la solution dépend des détails d'un système et d'une application.

A partir des commentaires il semble bibliothèque C++ est une possibilité, puis une solution basée sur std::vector (c.-à-generic vector of vectors in C++) ou en utilisant Boost.MultiArray

+0

Je ne suis pas sûr de comprendre votre extrait de code. L'allocation peut encore échouer, non? – batbrat

+0

@barbrat J'ai mis à jour ma réponse pour répondre à votre question – mloskot

7

Y aura-t-il beaucoup de valeurs par défaut dans votre ARRAY2D? Si oui, vous avez besoin d'un tableau clairsemé. Le changement minimal serait d'utiliser un unordered_map (ou hash_map ou map):

static const int numRows = 800000; 
static const int numCols = 300; 

struct ARRAY2D { 
    long col[numCols]; 
    // initialize a column to zero; not necessary. 
    ARRAY2D() { memset(col, 0, sizeof(col)); } 
}; 


// no need to malloc 
std::unordered_map<int, ARRAY2D> array; 
... 
// accessing is same as before ... 
array[1204].col[212] = 4423; 
printf("%d", array[1204].col[115]); 
... 
// no need to free. 

Si les indices de ligne sont toujours en continu mais beaucoup moins que numRows, utilisez un std::vector à la place.

std::vector<ARRAY2D> array; 
... 
// resize to the approach value. 
array.resize(2000); 
... 
// accessing is same as before ... 
array[1204].col[212] = 4423; 
printf("%d", array[1204].col[115]); 
... 
// no need to free. 
+0

Il y aura des valeurs par défaut dans certaines parties du tableau. Parfois, il y avait moins de lignes que numRows et moins de colonnes que numCols. – Brian

+0

OP a étiqueté avec C et C++, donc je suppose qu'il cherche une solution utilisable en C ainsi – mloskot

+1

Alors pourquoi l'a-t-il tagué C++? –

-2

Votre code contient des erreurs de syntaxe: il vous manque un point-virgule et long[] col; est invalide C ou C++ .

Étant donné:

struct ARRAY2D 
{ 
    long *col; 
}; 
ARRAY2D *array; 
int numRows = 800000; 
int numCols = 300; 
array = (ARRAY2D*) malloc(numRows * numCols * sizeof(long)); 

vous êtes potentiellement allouez la mauvaise quantité de mémoire: sizeof(long) devrait être remplacé par sizeof *array ou sizeof(ARRAY2D).

En supposant que vous avez la bonne quantité, vous pouvez indexer votre array comme: array[i], pour i dans la gamme [0, numRows*numCols). Vous n'avez alloué aucune mémoire pour col membres de l'un des array[i], donc vous ne pouvez pas indexer dans col de l'un de ceux-ci. Votre utilisation de array[row].col[colNum] est donc erronée compte tenu du schéma d'allocation que vous avez posté.

Peut-être que cela aiderait si vous avez posté du code réel qui fonctionne.

0

j'ai écrit un exemple simple, comment j'attribuerait le tableau en gros morceaux:

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

struct ARRAY2D { 
    long *col; 
    char free; 
}; 

struct ARRAY2D *ARRAY2D_malloc(int numRows, int numCols){ 
    struct ARRAY2D *rows = malloc(numRows * sizeof(struct ARRAY2D)); 
    if(rows){ 
    for(int i=0,b=numRows; i<numRows; i+=b){ 
     char *mem; 
     while(b && !(mem = malloc(b*numCols*sizeof(rows[0].col[0])))) b--; 
     if(b<1){ 
     while(--i >= 0) if(rows[i].free) free(rows[i].col); 
     free(rows); rows=NULL; break; 
     } 
     for(int j=i; j<i+b && j<numRows; j++){ 
     rows[j].free=(j==i); 
     rows[j].col = (void*)mem; mem += numCols*sizeof(rows[0].col[0]); 
     } 
    } 
    } 
    return rows; 
} 

int main(void){ 
    int numRows = 8000000; 
    int numCols = 300; 
    struct ARRAY2D *array = ARRAY2D_malloc(numRows, numCols); 
    if(array){ 
    printf("array[numRows-1].col[numCols-1]=%li\n", array[numRows-1].col[numCols-1]=3); 
    } 
    else{ 
    puts("not enough memory"); 
    } 
}

b est le nombre de lignes attribuées en une seule étape. La décrémentation b avec un est une stratégie simple lorsqu'il n'y a pas de gros blocs de mémoire libre.