Qual è la soluzione migliore per l'allocazione della memoria statica?

5

Sto lavorando all'elaborazione delle immagini e ho bisogno di usare immagini grandi in un sistema critico.

Una buona pratica per i sistemi critici è quella di evitare l'allocazione dinamica della memoria, ma qual è il progetto / i consigli per l'allocazione della memoria statica?

Se eseguiamo un'allocazione statica di una grande matrice, otteniamo un overflow dello stack.

class test
{
    public:
        test(){};
        ~test(){};

    private:
        float m_bigMatrix[3000000];
};

Per risolvere questo problema possiamo definire la matrice come statica, ma questa matrice sarà la stessa per tutte le istanze di questa classe.

static float m_bigMatrix[3000000];

L'altra soluzione è avere un oggetto statico.

static test t;

Ho una soluzione da un altro forum in cui è stato suggerito che il l'approccio migliore sarebbe utilizzare una classe specifica per la gestione della memoria.

Tutte le istanze della classe sono statiche e vengono utilizzate da altre classi nel codice.

Ecco una versione sciatta per questa soluzione (è solo un esempio):

class MemManager
{
public:
    MemManager(){ m_counter = 0u; }
    ~MemManager(){ printf("Out of MemManager nbr %d\n", m_counter); }

    uint16_t getCounter() { return m_counter; }
    uint16_t getData(uint32_t pos) { return m_data[pos]; }

    void setCounter(uint16_t val) { m_counter = val; }
    void setData(uint16_t val, uint32_t pos) { m_data[pos] = val; }

private:
    static const uint32_t MEM_SIZE_DATA = 100000000u;
    uint16_t m_counter;
    uint16_t m_data[MEM_SIZE_DATA];

protected:
};

class MemUser
{
public:
    MemUser(){ m_memManager = NULL; }
    ~MemUser(){ printf("Out of MemUser\n"); }

    void init(MemManager& memManager) { m_memManager = &memManager; };
    uint16_t getCounter() { return m_memManager->getCounter(); }
    uint16_t getData(uint32_t pos) { return m_memManager->getData(pos); }

    void setCounter(uint16_t val) { m_memManager->setCounter(val); }
    void setData(uint16_t val, uint32_t pos) { m_memManager->setData(val, pos); }

private:
    MemManager *m_memManager;

protected:
};

int main()
{
    static MemManager mManager;
    mManager.setCounter(1);
    {
        MemUser mUser;
        mUser.init(mManager);
        printf("Exit scope\n");
    }
    for(uint8_t i = 1u; i<5u; i++)
    {
        static MemManager mManager2;
        printf("Note that mManager2 is the same: %d\n", mManager2.getCounter());
        mManager2.setCounter(i);
    }
    printf("Exit process\n");
    return 0;
}

Quindi, è corretto? Qual è la soluzione migliore?

    
posta jblasius 29.07.2013 - 17:21
fonte

2 risposte

7

L'intero scopo di evitare l'allocazione dinamica della memoria è che se il tuo programma ha memoria sufficiente per completare l'inizializzazione, allora sai per certo che non colpirai una condizione di memoria esaurita nel bel mezzo del tuo programma, sotto un certo limite di condizioni a cui non avevi pensato.

Scrivi le tue sconfitte del gestore della memoria a vantaggio. In effetti, lo rende meno sicuro. Invece di esaurire l'heap con il gestore della memoria integrato che è altamente testato, ottimizzato e utilizzato da milioni di programmatori, si sta invece esaurendo la memoria su un gestore di memoria non testato, scritto da programmatori che probabilmente non hanno scritto una memoria gestore prima, e usato solo da te.

Se stai ricevendo overflow dello stack dal fatto che il tuo oggetto è troppo grande, la soluzione è non allocare l'oggetto nello stack, come in static test t; o static float m_bigMatrix[3000000]; . Sì, è fastidioso. Sì, va contro il tuo istinto da ciò che ti è stato insegnato come best practice sui sistemi non critici. Ecco come va.

Un compromesso che ho visto è di evitare solo la deallazione dinamica , e assicurarmi di eseguire tutta l'allocazione dinamica quando il programma si avvia per la prima volta. Questo lo fa sentire più naturale, ma ti dà comunque il vantaggio di una memoria nota vincolata. Tuttavia, è molto più difficile da controllare. Quando lavoravo prima su sistemi critici, questo era permesso solo in circostanze eccezionali.

    
risposta data 29.07.2013 - 19:37
fonte
2

Le immagini sono normalmente memorizzate non compresse - in genere 3 o 4 byte per pixel, ma possibilmente di più. Pertanto un'immagine da 12 megapixel richiede forse 48 megabyte di RAM. HDR ecc potrebbe richiedere un po 'di più, ma ancora non molto nel grande schema di cose.

Ero solito sistemare questo tipo di budget sui primi cellulari con fotocamera, quando era molto scarso e facevamo ogni tipo di trucco per ridurlo. Ma sui telefoni low-end di oggi, 48 MB sono semplicemente non molto .

Non creare codice complicato. Basta avere un array di byte per l'immagine. Concentrati sulla correttezza. Se non si dispone della RAM, non si tratta di una domanda di allocazione di memoria statica ma di una domanda di compressione o domanda di paging e presenta un livello di complessità completamente diverso.

    
risposta data 29.07.2013 - 17:36
fonte

Leggi altre domande sui tag