Newsgroup: it.comp.lang.c
Titolo: PROBLEMA con buffer grandi

Ho un piccolo problema, che non riesco a spiegarmi.
Uso MS VC++ 5.0, ed ho una applicazione di tipo console (circa 1000 righe).
Il PC e' un Pentium 133Mhz, 48Mbyte ram, quando lancio l'applicazione ho
un'occupazione di ram di ~30Mbyte (e quindi circa 18Mbyte liberi).
In una funzione, ho una cosa del tipo:
int funz(char *s, int i)
{
    int a, b, c;
    char buf[BIGBUF];
    ....
}
a seconda di come definisco BIGBUF, ottengo i seguenti comportamenti:
2 < BIGBUF < 204800  (200k)
    tutto bene.
2048000 < BIGBUF < 409600 (400k)
    l'applicazione parte e funziona, ma quando viene chiamata f()
l'applicazione
    va in stack overflow, tipicamente in un posto che non ha nulla a che
    vedere con buf (ad esempio in una printf che sta in un'altra funzione, o
in
    una memset 30 righe di codice dopo l'utilizzo di buf - queste info le
    recupero usando il debugger di VC)
409600 < BIGBUF
    l'applicazione parte, ma appena chiamo f() accadono gli errori piu
strani
    - da stack overflow (vedi sopra) a "the memory could not be read"  altri
che
    non ricordo.
Ho provato anche a dichiarare buf come var globale, in modo che venga
istanziata alla partenza del prg, ma senza esito (se non spostare gli errori
in punti del prg apparentemente casuali).
Perche' ho difficolta a allocare e usare 400k di buffer su una macchina che
ha ancora
18Mbyte di RAM libera, e che non sta neppure "swappando"??
Sta cosa mi fa davvero incaz..., come cavolo è possibile?
E perchè gli errori avvengono in punti del prg che nulla hanno a che vedere
con buf[]??
SE avessi bisogno di un buffer di 2/3 Mbyte, come faccio ad allocarmelo?
Preferirei NON usare la malloc, anche perchè il buffer è necessario, e se la
malloc
fallisce (ritorna NULL) devo gestire il caso ecc....
In altre parole, quello di cui ho bisogno è un buffer di un paio di Mbyte,
eventualmente anche sempre allocato (var globale), ma che non mi renda
"instabile" il programma.
Qualcuno sa aiutarmi a capirci qualche cosa?
TIA, e scusate per il lungo post.
Beppe

Dimenticavo, il S.O. e NT Server 4.0, SP 4,
e il problema si presenta tale e quale
anche su una macchina NT WS 4.0 SP 3, PentiumII 200 con 128Mbyte RAM
Grazie ancora a chiunque mi dara' suggerimenti e aiuto.
Beppe


ICQ #34602650

stack è limitato rispetto all'heap.
che differenza c'è fra stack e heap? quali sono le loro definizioni (almeno
"spannometricamente")
Scusa la domanda, ma io arrivo dal mondo UNIX, e din WIN32 ne capisco
abbastanza poco...
Grazie ancora,
Beppe

 abbastanza poco...
Il problema esiste anche negli unix.


"spannometricamente")
Lo stack e' la memoria in cui viene allocato e deallocato lo spazio
per i parametri e le variabili locali delle funzioni in modo
automatico.
La memoria heap e' invece quella in cui viene allocato e deallocato lo
spazio per il valore indirizzato dalle variabili puntatore, in modo
esplicito.
Generalmente il codice eseguibile generato dal compilatore viene
impostato per assumere uno stack di dimensione fissa e molto piu'
limitata che non quella della memoria heap, cioe' di tutta la memoria
disponibile al programma al momento della sua esecuzione.

Il problema esiste anche negli unix.
Sarà, ma non lo ho mai riscontrato.
Personalmente, sono più propenso a pensare ad un "difetto" del compilatore,
infatti:
// a.c
#include <stdio.h>
#include <string.h>
main()
{
    f();
}
f()
{
 char s[10240000];        // 10 Mbyte!
 strcpy(s, "pippo");
 printf("%s\n", s);
}
compilato sulla mia macchina NT con il gcc (porting ver 1.9 della Cygnus del
compilatore GNU)
produce un a.exe che fa esattamente quello che deve fare: stampa pippo.
Non ho a disposizione la macchina con il VC++, ma penso che provandoci, si
ottenga un
bello stack overflow... (questa sera ci provo, poi vi fo sapere).
In ogni caso, grazie ancora per le gentili tue spigazioni
Beppe

 Personalmente, sono più propenso a pensare ad un "difetto" del compilatore,
Non esattamente. Prova in project - settings - link - output a riservare
un quantitativo di stack adeguato (di default è 1M).


un quantitativo di stack adeguato (di default è 1M).
E' quello che ho fatto, giusto per fare un po' di esperienza (anche se poi
ho optato per una soluzione a mio avviso piu' elegante - calcolo quanto mi
serve ed uso malloc & free).
In ogni caso, il problema è risolto: le news si sono dimostrate ancora una
volta un ottimo strumento.
Ciao a tutti
Beppe

 Sarà, ma non lo ho mai riscontrato.
Mi intrometto per fare qualche precisazione.
Negli UNIX ogni processo eredita la dimensione max dello stack definita
dal genitore, e da li' non scappa a meno che non abbia diritti di root
(dunque, almeno in UNIX, il compilatore non c'entra).
Si puo', e anzi si deve, porre un limite di qualche MB per controllare
i processi impazziti, il cui superamento porta a un palese segmentation
fault.
La shell bash dispone di ulimit per impostare questo limite.  L'infinito
lo si tocca con "ulimit -s unlimited", il che' credo che estenda il max
a 2 GB sui processori i386.
Tutto cio' forse non c'entra nulla col problema specifico, ma almeno
emerge che non ci sono sostanziali limiti hw alla estensione dello
stack. Semmai bisogna indagare sul compilatore e sul SO specifico.
Ciao,
- Umberto

 char s[10240000];        // 10 Mbyte!
Veramente 10 Mbyte equivalgono a 10485760 byte.

bel warning se tale max è > della definizione dello stack in quel momento.
Supponi di avere :
int func ( long a, long b, ... ) ;
Come fai a calcolare il "MAX teorico" ?


OK, 10Mbyte scarsi, ma il senso del post non cambia.

...

E' un caso al quale non avevo pensato, hai ragione.

- Umberto
Ciao, Beppe

 - Umberto
Io una volta ho provato con un Pentium 166 a installare Linux
Slackware versione 3.3 impostando 128 Mb per la partizione di Swap.
ho provato a compilare un programma del tipo:
char a[10000000];
void f(void) {
}
int main(void) {
    f();
    return 0;
}
In questo modo tutto andava bene, ma all'aumentare della dimensione di a,
il linker divendava piuttosto nervoso, tanto che per dimensioni di a 
ad esempio di
200000000 byte ottenevo un errore del tipo
Virtual memory exausted 
Quindi,  anche se non ci sono limiti hw, ci sono comunque dei limiti
(memoria virtuale disponibile).
Cioe` se l'array fosse all'interno del corpo della funzione f,
a seguito della chiamata di tale funzione, si cercherebbe di costruire un
record di attivazione (quella zona in cui vengono inserite le variabili locali
e una copia dei parametri) di dimensioni maggiori della dimensione della
memoria virtuale disponibile!!
Marco Guidi.

 ho 48MB RAM + 100MB swap?
Non puoi. Ma nulla ti impedisce di:
1) comprare tanta RAM;
2) fare tante partizioni di swap;
3) ricondurre il programma alla ragione e ad essere piu' parco di risorse :-)
Ciao,
- Umberto

- Umberto
Ciao, e grazie
Bp


Ripensandoci pero', qualcosa lo si puo' calcolare, ed è il minimo necessario
nella peggiore delle ipotesi (per il tuo esempio, 2 * sizeof(long) ), anche
se ne riconosco la scarsa validità come stima dello stack necessario... e
per giunta l'occupazione dello stack è influenzata anche dalle chiamate a
funzione, e quelle non è possibile prevederle (Marco Sarti citava
giustamente le funzioni ricorsive, in qualche post fa)
Ciao,
    Beppe

ho 48MB RAM + 100MB swap?
Vorrei proprio sapere a che puo' servire uno stack di 2GB !!!! ;)


A nulla,
era un esempio appositamente forzato, come ho gia detto.
Il problema era l'affermazione "non ci sono sostanziali limiti hw alla
estensione dello stack2", ma e' gia stato chiarito.
Beppe

nella peggiore delle ipotesi (per il tuo esempio, 2 * sizeof(long) ),
Diciamo pure qualcosa in piu', perche' bisogna tener conto dei vari
push e pop che si eseguono sullo stack all'entrata e all'uscita di una
funzione.
Ma sinceramente non ne vedo l'utilita'.

 Vorrei proprio sapere a che puo' servire uno stack di 2GB !!!! ;)
Ma come, non lo sai? E' il requisito minimo di Windows 2000. :-)))
EMG

 Vorrei proprio sapere a che puo' servire uno stack di 2GB !!!! ;)
Funzioni ricorsive? :)

Funzioni ricorsive? :)
In tal caso sarebbe meglio rivedere il codice ! ;)