Newsgroup: it.comp.programmare.win32
Titolo: malloc in VC

Salve a tutti,
  ho la necessita' di riallocare un vettore di long durante alcune
elaborazioni e, piu' o meno, la dimensione max. raggiungibile e'  di
circa 2000000 elementi.
Facendo delle prove del tipo: 
...
dichiaro e alloco buf
...
 if( !(buf=(long *)realloc(buf,sizeof(long)*(N))) )
 { /* errore */ }
...
free(buf);
...
 ho visto che in VC6 l'allocazione arriva a un massimo di  N = 1474547
(poi realloc inizia a restituire NULL) mentre con DEVC arriva
tranquillamente a N = 2500000 (oltre non ho provato).
Esiste qualche opzione da passare al compilatore VC per riservare piu'
memoria (tipo i modelli SMALL, LARGE ecc... che c'erano una volta) ?
O che altro ?
Grazie.

, 
mimmo....@NOSPAMlibero.it says...

Visto che stai usando Win32 perche' non chiami la HeapRealloc? Se lo fai 
su un heap creato growable Win automaticamente chiama la VirtualAlloc se 
non ha abbastanza spazio nello heap. Per maggiori info guarda la 
documentazione di HeapCreate, HeapAlloc, HeapDestroy, HeapFree e 
HeapReAlloc.
Luca

HeapReAlloc.
Innanzitutto grazie per la risposta,
purtroppo ho fatto la prova anche con HeapXXXX ma ottenendo gli stessi
risultati:
...
  hHeap=HeapCreate(HEAP_NO_SERIALIZE,0,0); 
  if(!(buf=(long*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(long)))) 
   { /* errore */}
 ...
ecc...
....
if(!(buf=(long*)HeapReAlloc(hHeap,!(HEAP_REALLOC_IN_PLACE_ONLY),buf,sizeof(long)*(N))))
   { /* errore */}
...
ecc.
Nota: con il secondo argomento di HeapReAlloc  ho fatto varie prove
(ad es. usando solo HEAP_ZERO_MEMORY) ma nulla e' cambiato.
Intanto ho scoperto che, sia con DEVC che con lo stesso VC ma creando
un programma W32Console, riesco ad allocare (utilizzando alloc e
realloc) anche per N=50.000.000 
Non ho idea di cosa succeda...

 circa 2000000 elementi.
Il problema č cha la realloc deve estendere l'area di dati preallocata e
questo puň facilmente risultare impossibile.
Per esempio che cosa succede se dopo la prima area allochi anche un solo
byte? Che l'area precedente non puň piů essere estesa.
Potresti:
1) gestire array linkati!
2) usare VirtualAlloc
Ignoriamo il punto 1 :-)
Windows (o meglio la CPU) supporta la memoria virtuale ==> pagine
(generalmente di 4 KiB) continue nella memoria potrebbero (anzi č piuttosto
probabile) non esserlo nella memoria fisica.
Ma tanto ci pensa la CPU a traslare indirizzi logici in lineari e lineari in
fisici, giusto?
Allora con VirtualAlloc ti riservi degli indirizzi lineari:
LPVOID VirtualAlloc(
    LPVOID lpAddress, // address of region to reserve or commit
    DWORD dwSize, // size of region
    DWORD flAllocationType, // type of allocation
    DWORD flProtect  // type of access protection
    );
void *addr = VirtualAlloc(0, 100*1024*1024, MEM_RESERVE, PAGE_READWRITE);
In questo modo non hai allocato memoria fisica, ma ti sei assicurato che
NESSUNO allochi memoria all'interno del blocco [addr, addr+100*1024*1024-1].
A questo punto, con chiamate successive alla VirtualAlloc (questa volta
specificando MEM_COMMIT) puoi allocare le pagine che ti servono
(specificando l'indirizzo di partenza corretto e la dimensione...con 4096*2
per es. allochi 2 pagine)
Potresti addirittura allocare soltanto le pagine centrali, poi liberarle
quando non ti servono piů, ecc...
Ovviamente dovrai farti un mini gestore di pagine (basta che ti ricordi
quanto sono lunghe le pagine [puoi ottenere la dimensione delle pagine con
GetSystemInfo]).
Kiuhnm

Scusa, correggo quanto ho detto:
 ho scoperto che il problema si ha (sia con alloc che con HeapAlloc)
quando invece di fare un realloc "secco" faccio crescere poco a poco
il vettore.
E lo stesso comportamento lo hanno sia il DEVC che il VC. Quindi mi sa
che sono io che sbaglio in qualcosa.
Allora posto il codice:
#include <stdio.h>
#include <stdlib.h>
#include "malloc.h"
#define NMAX 2000000 // elementi da allocare
 
int main()
{ 
 long *buf;
 long k;
 if( !(buf=(long *)malloc(sizeof(long))) )   // inizializza
  { printf("Errore in malloc \n"); return 1; }
 printf(" Elaborazione in corso... \n");
 for(k=0; k<NMAX; k++)
   {
    if( !(buf=(long *)realloc(buf,sizeof(long)*(k+1))) )
     {
      printf("Errore in realloc \n");
      break; // esce dal for 
     }
    else
     {
      buf[k]=k; // giusto per fare qualcosa
     }
   }
 // mostra il risultato
 printf(" Elementi richiesti -->  n = %ld \n",NMAX); 
 printf(" Elementi allocati  -->  n = %ld \n",k); 
 system("PAUSE");	
 return 0;
}
Nota: se tolgo il for e rialloco direttamente per k=NMAX-1 elementi va
tutto benone !
Perche' ?
(Lo so che e' dispendioso fare il realloc tante volte, ma vorrei solo
capire perche' non gira...)
Arigrazie.
P.S. Ho aperto un thread analogo ("realloc in un for") in
it.comp.lang.c perche' appunto solo ora mi sono accorto che non era un
comportamento specifico del del VC.

byte? Che l'area precedente non puň piů essere estesa.
Mi sa che, mentre io postavo la replica al messaggio di Luca, hai
perfettamente centrato il problema.
Quello che dici credo che spieghi perfettamente quello che ho appena
postato.
Grazie a te e a Luca (e a chi continua a rispondere).

 volta) ? O che altro ?
per allocare cose grosse lascia stare completamente malloc e gli heap 
in genere, usa VirtualAlloc. Riservati un bel po' di memoria, e poi fai 
il commit di quella che man mano ti serve
-- 
 < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
     Don't stand, REACT!      version 0.0.20. C, C++ and ASM developers
                              and beta testers are welcome!