2011-08-25 8 views
9

Durante lo sviluppo di un pezzo di software per sistemi embedded che ho usato realloc() funzione molte volte. Ora mi è stato detto che "non dovrei usare realloc() in embedded" senza alcuna spiegazione.Realloc() è sicuro nel sistema embedded?

È realloc() pericoloso per sistemi embedded e perché?

+2

Perché non chiedi a chi te l'ha detto? – cnicutar

+3

In questi giorni Embedded è un'area molto ampia. –

+0

@cnicutar se potessi chiedere loro, non lo chiederò mai qui .. !! –

risposta

19

Sì, tutta l'allocazione dinamica della memoria è considerata pericolosa ed è vietata dalla maggior parte dei sistemi embedded "ad alta integrità", ad esempio industriale/automobilistico/aerospaziale/tecnico-elettronico ecc. La risposta alla tua domanda dipende da cosa una sorta di sistema incorporato che stai facendo.

Le ragioni per cui è stato bandito da sistemi embedded ad alta integrità non sono solo le potenziali perdite di memoria, ma anche un sacco di comportamenti pericolosi indefiniti/non specificati/impl.defined associati a tali funzioni.

EDIT: ho anche dimenticato di dire la frammentazione heap, che è un altro pericolo. Inoltre, MISRA-C menziona anche "incoerenza dei dati, esaurimento della memoria, comportamento non deterministico" come ragioni per le quali non dovrebbe essere usato. I primi due sembrano piuttosto soggettivi, ma il comportamento non deterministico è sicuramente qualcosa che non è permesso in questo tipo di sistemi.

Riferimenti:

  • MISRA-C: 2004 Regola 20.4 "allocazione di memoria heap dinamica non devono essere utilizzati"
  • IEC 61508 sicurezza funzionale, 61508-3 allegato B (normativa) Tabella B1,> SIL1: "Nessun oggetti dinamici", "Nessun variabili dinamiche".
+4

Questa è l'unica buona risposta. Non si dovrebbe mai utilizzare la memoria heap nei sistemi incorporati. Inserisci tutti i dati nella sezione dati, bss o in pila. In questo modo hai un ingombro di memoria di dimensioni fisse e puoi calcolare l'utilizzo della memoria. In questo modo sai con certezza quanta memoria stai effettivamente usando e non puoi mai superare quel limite. L'utilizzo dell'heap è il vettore più comune nel rendere i sistemi incorporati in crash dopo un'esecuzione prolungata. – DipSwitch

+4

Ho compreso la domanda in relazione a realloc() in particolare, non sull'utilizzo dell'allocazione dinamica della memoria o meno. – pmod

+0

@DipSwitch - L'utilizzo dell'heap causa l'arresto anomalo? o l'uso non valido di heap causa crash? senti la differenza .. puoi farlo molto più facilmente - usando erroneamente dei puntatori .. - dovremmo disabilitare i puntatori? – pmod

5

Dipende dal particolare sistema embedded. gestione dinamica della memoria su un sistema embedded piccolo è difficile per cominciare, ma realloc più complicato che è un free e malloc (naturalmente, questo non è ciò che fa). Su alcuni sistemi embedded non ci si potrebbe mai sognare di chiamare malloc in primo luogo. Su altri sistemi embedded, fai quasi finta di essere un desktop.

Se il sistema incorporato ha un allocatore scadente o non molta RAM, allora realloc potrebbe causare problemi di frammentazione. Ecco perché si evita anche lo malloc, perché causa gli stessi problemi.

L'altro motivo è che alcuni sistemi incorporati devono essere altamente affidabili, e malloc/realloc può restituire NULL. In queste situazioni, tutta la memoria viene allocata staticamente.

+0

Non sono un ragazzo incorporato, ma sembra che tu stia uscendo per le tangenti sulla libertà e malloc. Realloc è potenzialmente molto più di questo, è solo che l'interfaccia è semplice. –

+0

Stavo dicendo che non era * più * complicato di malloc e gratuito, non che fosse in qualche modo composto da loro. Mi dispiace se la mia formulazione imprecisa merita la tua disapprovazione. –

0

Ebbene, è meglio evitare di usare realloc se è possibile, poiché questa operazione è costosa, soprattutto in fase di messa in ciclo: per esempio, se una memoria allocata deve essere esteso e non c'è spazio tra dopo blocco attuale e il prossimo blocco assegnato - questa operazione è quasi uguale a: malloc + memcopy + free.

+2

'' realloc() 'è peggio di' malloc() '/' free() '? – sharptooth

+0

voglio anche chiedere a questo –

+0

Peggio perché la riallocazione può essere ottimizzata usando blocchi di memoria adiacenti, ma questo naturalmente non è sempre possibile – pmod

2
  1. realloc può fallire, proprio come malloc can. Questo è uno dei motivi per cui probabilmente non dovresti utilizzarlo in un sistema embedded.

  2. realloc è peggiore di malloc a che sarà necessario avere i vecchi e nuovi puntatori valide alla realloc. In altre parole, sarà necessario 2 volte lo spazio di memoria dell'originale malloc, più qualsiasi importo aggiuntivo (supponendo che realloc aumenti la dimensione del buffer).

  3. L'utilizzo di realloc sarà molto pericoloso, in quanto potrebbe restituire un nuovo puntatore alla posizione di memoria. Ciò significa:

    • Tutti i riferimenti al vecchio puntatore devono essere corretti dopo realloc.
    • Per un sistema multi-thread, realloc deve essere atomico. Se si disattivano gli interrupt per raggiungere questo obiettivo, il tempo realloc potrebbe essere abbastanza lungo da causare un reset dell'hardware da parte del watchdog.

Aggiornamento: Volevo solo mettere in chiaro. Non sto dicendo che realloc è peggio di attuazione realloc utilizzando un malloc/free. Sarebbe altrettanto brutto. Se è possibile eseguire un singolo malloc e free, senza ridimensionarlo, è leggermente migliore, ma comunque pericoloso.

+0

I punti 2 e 3 non si applicano alla chiamata manuale di 'malloc()'/'free()' ? – sharptooth

+0

3. è un buon punto, realloc è davvero più pericoloso di malloc per quel motivo, anche se il malloc da solo è considerato troppo pericoloso per cominciare. – Lundin

+0

@sharptooth - A destra, realloc sta solo facendo malloc/free in alcuni casi. Quindi la mia risposta cerca di spiegare che realloc non è magico e pericoloso. Potrebbe non essere chiaro dove sono i draghi, a meno che non si implementi realloc usando l'API malloc/free. Volevo solo richiamare direttamente il sovraccarico della memoria. – cmcginty

1

I problemi con realloc() nei sistemi incorporati non sono diversi rispetto a qualsiasi altro sistema, ma le conseguenze potrebbero essere più gravi nei sistemi in cui la memoria è più limitata e le conseguenze dell'errore meno accettabili.

Un problema non menzionato finora è che realloc() (e qualsiasi altra operazione di memoria dinamica del caso) è non deterministico; questo è il tempo di esecuzione è variabile e imprevedibile. Molti sistemi incorporati sono anche sistemi in tempo reale e in tali sistemi il comportamento non deterministico è inaccettabile.

Un altro problema è quello di filo di sicurezza. Controlla la documentazione della tua libreria per vedere se la tua libreria è sicura per i thread per l'allocazione dinamica della memoria. In genere, se lo è, sarà necessario implementare mutex stub per integrarlo con la libreria di thread o RTOS.

Non tutti emebdded sistemi sono uguali; se il tuo sistema embedded non è in tempo reale (o il processo/attività/thread in questione non è in tempo reale, ed è indipendente dagli elementi in tempo reale), e hai una grande quantità di memoria inutilizzata, o capacità di memoria virtuale, quindi l'uso di realloc() può essere accettabile, se forse non consigliato nella maggior parte dei casi.

Piuttosto che accettare "saggezza convenzionale" e barra di memoria dinamica a prescindere, è necessario comprendere i requisiti di sistema, e il comportamento delle funzioni di memoria dinamica e prendere una decisione appropriata. Detto questo, se si sta costruendo codice per la riutilizzabilità e la portabilità su una vasta gamma di piattaforme e applicazioni possibili, allora la riallocazione è probabilmente una pessima idea. Ad esempio, non nasconderlo in una libreria.

Nota anche che lo stesso problema esiste con C++ classi container STL che riallocazione dinamicamente e copiare i dati quando si aumenta la capacità del contenitore.

4

In molti sistemi embedded, un gestore di memoria personalizzato in grado di fornire la semantica migliori rispetto sono disponibili con malloc/realloc/libero. Alcune applicazioni, ad esempio, possono essere utilizzate con un semplice allocatore di mark-and-release. Tenere un puntatore all'inizio della memoria non ancora allocata, allocare le cose spostando il puntatore verso l'alto e rilasciarle spostando il puntatore sotto di esse. Ciò non funzionerà se è necessario gettare alcune cose mantenendo altre cose che sono state assegnate dopo di esse, ma in situazioni in cui ciò non è necessario, l'allocatore di mark-and-release è più economico di qualsiasi altro metodo di allocazione.In alcuni casi in cui l'allocatore di mark-and-release non è abbastanza buono, può essere utile allocare alcune cose dall'inizio dell'heap e altre cose dalla fine dell'heap; uno può liberare le cose assegnate da un capo senza influenzare quelle assegnate dall'altro.

Un altro approccio che può talvolta essere utile nei sistemi di multitasking o di multitasking cooperativo consiste nell'utilizzare handle di memoria anziché puntatori diretti. In un tipico sistema basato su handle, c'è una tabella di tutti gli oggetti allocati, costruiti nella parte superiore della memoria che funziona verso il basso e gli oggetti stessi sono allocati dal basso verso l'alto. Ogni oggetto allocato in memoria contiene un riferimento allo slot della tabella che lo fa riferimento (se in diretta) oppure un'indicazione della sua dimensione (se morto). La voce della tabella per ogni oggetto manterrà la dimensione dell'oggetto e un puntatore all'oggetto in memoria. Gli oggetti possono essere allocati semplicemente trovando uno slot di tabella libero (facile, poiché gli slot di tabella sono tutte di dimensioni fisse), memorizzando l'indirizzo dello slot di tabella dell'oggetto all'inizio della memoria libera, archiviando l'oggetto stesso oltre a quello e aggiornando l'inizio di memoria libera per puntare appena oltre l'oggetto. Gli oggetti possono essere liberati sostituendo il riferimento all'indietro con un'indicazione della lunghezza e liberando l'oggetto nella tabella. Se un'assegnazione fallirebbe, riposizionare tutti gli oggetti attivi a partire dalla parte superiore della memoria, sovrascrivendo eventuali oggetti morti e aggiornando la tabella degli oggetti in modo che punti ai loro nuovi indirizzi.

Le prestazioni di questo approccio non sono deterministiche, ma la frammentazione non è un problema. Inoltre, in alcuni sistemi cooperativi multitasking potrebbe essere possibile eseguire "garbage collection" in background "; a condizione che il garbage collector possa completare un passaggio nel tempo necessario per far passare lo spazio allentato, è possibile evitare lunghe attese. Inoltre, alcune logiche "generazionali" abbastanza semplici possono essere utilizzate per migliorare le prestazioni del caso medio a scapito delle prestazioni nel caso peggiore.

Problemi correlati