web-dev-qa-db-ja.com

静的メモリ割り当ての最適なソリューションは何ですか?

私は画像処理に取り組んでおり、重要なシステムで大きな画像を使用する必要があります。

重要なシステムの良い習慣はメモリの動的割り当てを避けることですが、静的メモリ割り当ての設計/推奨は何ですか?

大きな行列の静的割り当てを行うと、スタックオーバーフローが発生します。

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

    private:
        float m_bigMatrix[3000000];
};

この問題を解決するには、マトリックスを静的として定義できますが、このマトリックスは、このクラスのすべてのインスタンスで同じになります。

static float m_bigMatrix[3000000];

他の解決策は、静的オブジェクトを持つことです。

static test t;

私は別のフォーラムから解決策を得ました。そこでは、最善のアプローチはメモリ管理に固有のクラスを使用することであると提案されました。

クラスのすべてのインスタンスは静的であり、コード全体で他のクラスによって使用されます。

これがこのソリューションのずさんなバージョンです(これは単なる例です)。

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;
}

それで、これは正しいですか?最良の解決策は何ですか?

6
jblasius

動的メモリ割り当てを回避する重要な点は、初期化を完了するのに十分なメモリがプログラムにある場合、プログラムの途中で、一連の境界条件の下で、メモリ不足状態に陥らないことが確実にわかるということです。考えていなかった。

独自のメモリマネージャを作成することは、その利点を打ち負かします。実際、それはless安全にします。高度にテスト、最適化され、何百万人ものプログラマーが使用する組み込みのメモリマネージャーでヒープが不足する代わりに、おそらくメモリを作成していないプログラマが作成した、テストされていないメモリマネージャーでメモリが不足しています以前はマネージャーで、あなただけが使用していました。

オブジェクトが大きすぎるためにスタックオーバーフローが発生する場合の解決策は、static test t;またはstatic float m_bigMatrix[3000000];のように、オブジェクトをスタックに割り当てないことです。はい、それは迷惑です。はい、それはあなたが教えられてきたものからのあなたの本能に反します、重要でないシステムでのベストプラクティスです。それだけです。

私が目にした妥協の1つは、動的deallocationのみを回避し、プログラムが最初に起動するときにすべての動的割り当てを実行することです。これにより、より自然に感じられますが、それでも既知のメモリバウンドの利点が得られます。ただし、監査するのははるかに困難です。以前に重要なシステムで作業していたとき、これは非常に例外的な状況でのみ許可されました。

8
Karl Bielefeldt

画像は通常、非圧縮で保存されます。通常、ピクセルあたり3バイトまたは4バイトですが、それ以上の可能性もあります。したがって、12メガピクセルの画像には、48メガバイトのRAMが必要になります。 HDRなどはもっと時間がかかるかもしれませんが、それでもそれほど多くないは、物事の大きなスキームでは必要です。

私は初期のカメラ付き携帯電話でこの種の予算を整理していましたが、それは恐ろしくて、私たちはそれを減らすためにあらゆる種類のトリックを行いました。しかし、今日のローエンドの電話では、48 MBは単純にそれほど多くないです。

複雑なコードを作成しないでください。画像のバイト配列を用意するだけです。正確さに焦点を当てます。 RAMがない場合、これは静的メモリ割り当ての問題ではなく、圧縮またはデマンドページングの問題であり、まったく異なるレベルの複雑さです。

2
Will