C'è uno svantaggio nell'allocare una grande quantità dello stack per un singolo array in un sistema incorporato?


12

Di solito non ho problemi a decidere se alcuni dati devono essere globali, statici o in pila (nessuna allocazione dinamica qui, quindi nessun uso dell'heap). Ho anche letto alcuni Q / A come questo, ma la mia domanda è più specifica in quanto comporta un'enorme quantità di dati, enorme rispetto alla memoria di sistema.

Sto lavorando a un codice esistente che cerco di migliorare (design, possibili problemi, prestazioni, ecc.). Questo codice viene eseguito su un vecchio MCU a 8 bit con solo 4KB di RAM . In questo codice devo affrontare l'uso di un array di quasi 1 KB (sì, 1 KB su un sistema RAM 4KB ). Viene utilizzato ogni byte di questo array, non è questa la domanda. Il problema è che questo array è un array statico nel file in cui è dichiarato, quindi il suo ciclo di vita è lo stesso di quello del programma (cioè può essere considerato infinito).

Tuttavia, dopo aver letto il codice, ho appena scoperto che questo array non ha bisogno di un ciclo di vita infinito, è costruito e gestito in modo completamente procedurale, quindi dovremmo essere in grado di dichiararlo solo nella funzione in cui viene utilizzato, in questo modo sarebbe nello stack e quindi risparmieremmo 1 KB di RAM.

Ora la domanda: sarebbe una buona idea? Dal punto di vista del design, se non ha bisogno di un ciclo di vita infinito / globale, appartiene allo stack. Ma hey, questo è 1KB su 4KB, non c'è alcun inconveniente di allocare il 25% della RAM in questo modo? (potrebbe essere il 50% o più dello stack)

Qualcuno potrebbe condividere qualche esperienza con questo tipo di situazione o qualcuno potrebbe pensare a qualche motivo valido per non mettere questo array in pila? Sto cercando svantaggi tecnici e commenti sul design.

L'unica cosa di cui sono consapevole è che devo assicurarmi di avere 1 KB di stack gratis quando si accede a questa funzione. Forse è tutto ciò di cui devo occuparmi, forse no.


4
Hai scritto "e quindi salvare questo 1 KB di RAM". Salvalo per cosa? Quel 1KB deve essere disponibile quando è necessario per l'array, quindi perché non effettuare un'allocazione statica? Hai un altro uso della memoria quando non è necessario per l'array?
kkrambo,

@kkrambo Ad un certo punto consideriamo un sistema pieno quando non possiamo aggiungere altro sulla RAM, sia esso statico o nello stack. Se mettessimo questo array nello stack solo quando lo usiamo, lascerebbe spazio a un'altra funzionalità purché non vengano utilizzati contemporaneamente. Ma la domanda è totalmente legittima, al momento se non cambiamo nulla nel SW, non abbiamo bisogno di più RAM;)
Tim

1
Potresti chiarire se questo array ha un contenuto che rimane sempre lo stesso o se cambia quando viene invocata la funzione che lo utilizza?
Blrfl,

@Blrfl Cambia ogni volta che viene chiamata la funzione.
Tim

Risposte:


8

L'unica cosa di cui sono consapevole è che devo assicurarmi di avere 1 KB di stack gratis quando si accede a questa funzione.

Sì, e questo è un forte vincolo. Farai meglio a essere staticamente sicuro di quanto tu abbia uno spazio così grande disponibile nello stack. Se il codice è piccolo, se si utilizza un GCC recente per compilare il codice, vedere questo .

A proposito, alcuni microprocessori economici potrebbero utilizzare un frame di chiamata "grande" più costoso di uno "normale" (ad esempio perché il loro set di istruzioni favorirebbe un offset di un byte dal puntatore dello stack). YMMV.

Inoltre, se stai codificando in C e se ritieni che il tuo array di grandi dimensioni possa avere il suo spazio riutilizzato per altri scopi, potresti considerare di renderlo un membro del sindacato (con una variabile globale di uniontipo). Sì, è abbastanza brutto.

In alternativa, potresti prendere in considerazione la codifica di un allocatore di heap primitivo adatto alla tua applicazione (e potrebbe avere un'API diversa da malloc& free....).


1
Grazie, in realtà mi aspettavo un po 'questo tipo di risposta, vale a dire tenerlo staticamente allocato in modo da essere sicuro di non finire con un overflow dello stack. Purtroppo non ho un compilatore GCC recente e il codice non è piccolo.
Tim

Non riesci a ottenere (forse compilando GCC dal suo codice sorgente) un compilatore GCC per la tua piattaforma?
Basile Starynkevitch,

2
Ne ho già uno, è davvero vecchio. Lavorare su uno nuovo non rientra nel mio ambito di applicazione, né si adatterebbe al mio programma. Ma certo, alcune cose sarebbero più facili con strumenti aggiornati.
Tim

3
Chiedere al tuo capo di procurarti un GCC più recente (fornendoti strumenti binari aggiornati o dandoti tempo per la ricompilazione di GCC) vale la pena IMHO, perché molto probabilmente il GCC più recente ottimizzerebbe leggermente meglio (lo sai gcc -flto -Os? ) e potresti guadagnare un po 'di memoria ....
Basile Starynkevitch l'

2
È sulla buona strada ma non arriverà prima. Uso già -Os su altri sistemi con toolchain più recenti, ma non ero a conoscenza di questo parametro -flto, grazie per averlo sottolineato. (Nota che ho fatto alcuni test con GCC -Os e -O1-3 qualche settimana fa su GCC 5.4.1 e la RAM era sempre la stessa. Il tempo di esecuzione di FLASH e MCU era diverso. Quello non era sullo stesso MCU di quello che menziono in questo Q / A)
Tim

6

Le persone tendono ad essere caute con un grosso stack, perché cresce all'indietro nella RAM e sovrascrive i valori delle variabili, portando a comportamenti inspiegabili. Peggio ancora, perché è necessario conoscere l'indirizzo del puntatore dello stack più basso possibile e sottrarre le dimensioni da allocare quando si accede alla routine.

Questo è tutto un lavoro per la gestione della memoria hardware (dovrebbe generare trap o guasti quando si verifica un overflow dello stack) o per il compilatore, dato che ha funzionalità per questo tipo di analisi.

Altrimenti, puoi fare quello che vuoi con la tua RAM.


4

Come hanno sottolineato le risposte precedenti, consiglierei innanzitutto di lasciare l'array statico se si adatta alla memoria. Nella maggior parte dei casi, è molto più importante avere un footprint di memoria deterministico, anche se ciò significa che "sprechi" la memoria per le variabili che non vengono sempre utilizzate. Mettere array di grandi dimensioni nel tuo stack lo farà esplodere troppo facilmente e gli overflow dello stack tendono a causare problemi difficili da trovare e da riprodurre (se non puoi utilizzare MMU per proteggere lo stack).

Il suggerimento di condividere il blocco con alcuni altri dati con union è valido IMO, sebbene possa anche essere fonte di problemi difficili da trovare, se si individuano variabili errate in esso.

Se stai esaurendo la memoria e hai disperatamente bisogno di creare variabili a vita più breve per condividerlo, prima di spostare l'array in pila, prenderei in considerazione l'aggiunta di allocazione dinamica della memoria, anche se ha i suoi svantaggi. In questo caso potrebbe non essere una risposta, poiché l'array suona piuttosto grande rispetto alla memoria disponibile.


1

Hai un'altra opzione se hai qualche tipo di memoria flash. È possibile compromettere la velocità di accesso per ram memorizzando i dati in flash e leggendo e cercando lì. Dovresti solo caricare un record alla volta in RAM. Sarà leggermente più complicato se devi essere in grado di aggiornare i record. Avrai bisogno di un meccanismo segmentato a livello di usura. L'ho fatto in passato e ho incluso un indice per accelerare l'accesso.


1
L'ho fatto anche in passato, ma la mia domanda era più sui problemi che potrei affrontare se lo mettessi nello stack, non sulle alternative alla RAM quando ne siamo a corto. Grazie per aver risposto comunque
Tim

1

Soprattutto quando si lavora con i sistemi embedded, si desidera che si verifichino la maggior parte dei possibili errori in fase di compilazione e nulla non si guasta mai in fase di esecuzione (bello se potessimo riuscirci, però ...).

Creare array di grandi dimensioni che potrebbero essere necessari in stati arbitrari del programma allocati staticamente fa esattamente questo: il linker alla fine ti avviserà "questo non si adatta alla RAM", mentre l'allocazione dello stack renderebbe semplicemente il crash del tuo programma con stack difficili da debug overflow.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.