簡體   English   中英

我找不到的 C++ 內存泄漏

[英]C++ memory leak that I can't find

我這里有一個小示例程序,用於粒子光子,它有一個我無法弄清楚的內存錯誤。

它的作用:加載帶有小字符串塊的緩沖區,將該大緩沖區轉換回字符串。 然后它創建了一堆對象,這些對象只是小塊緩沖區的包裝器。 它重復執行此操作,並且在 setup() 之后我不會分配任何新內存,但內存會緩慢下降直到崩潰。

主程序

包括,變量聲明

#include "application.h" //needed when compiling spark locally

#include <string>
#include <unordered_map>
#include "dummyclass.h"

using namespace std;
SYSTEM_MODE(MANUAL);

char* buffer;
unordered_map<int, DummyClass*> store;
string alphabet;
unsigned char alphabet_range;
unsigned char state;
int num_chars;

static const unsigned char STATE_INIT = 0;
static const unsigned char STATE_LOAD_BUFFER = 1;
static const unsigned char STATE_PREP_FOR_DESERIALIZE = 2;
static const unsigned char STATE_FAKE_DESERIALIZE = 3;
static const unsigned char STATE_FINISH_RESTART = 4;

刪除對象輔助函數

bool delete_objects()
{
    Serial.println("deleting objects in 'store'");
    for(auto iter = store.begin(); iter != store.end(); iter++)
    {
        delete iter->second;
        iter->second = nullptr;
    } 
    store.clear();

    if(store.empty())
        return true;
    else
        return false;
}

設置函數,分配內存,初始分配

void setup()
{
    Serial.begin(9600);
    Serial1.begin(38400);
    delay(2000);

    buffer = new char[9000];
    alphabet = string("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$^&*()_-?/><[]{}|");
    alphabet_range = alphabet.length() - 1;
    state = STATE_INIT;
    num_chars = 0;
}

循環功能,一遍又一遍地運行

void loop()
{
    switch(state){
        case STATE_INIT: {

            strcpy(buffer, "");
            state = STATE_LOAD_BUFFER;
            delay(1000);
            break;

        }
        case STATE_LOAD_BUFFER: {

            if(num_chars < 6000){
                string chunk;
                for(char i = 0; i < 200; i++){
                    int index = rand() % alphabet_range;
                    chunk.append(alphabet.substr(index, 1));
                    num_chars++;
                }
                strcat(buffer, chunk.c_str());
            }
            else{
                num_chars = 0;
                state = STATE_PREP_FOR_DESERIALIZE;
            }
            delay(500);
            break;

        }
        case STATE_PREP_FOR_DESERIALIZE: {

            Serial.println("\nAttempting to delete current object set...");
            delay(500);
            if(delete_objects())
                Serial.println("_delete_objects succeeded");
            else {
                Serial.println("_delete_objects failed");
                break;
            }
            state = STATE_FAKE_DESERIALIZE;
            delay(1000);
            break;

        }
        case STATE_FAKE_DESERIALIZE: {

            string buff_string(buffer);
            if(buff_string.length() == 0){
                Serial.println("Main:: EMPTY STRING CONVERTED FROM BUFFER");
            }

            int index = 0;
            int key = 1;
            while(index < buff_string.length())
            {
                int amount = (rand() % 50) + 5;
                DummyClass* dcp = new DummyClass(buff_string.substr(index, amount));
                store[key] = dcp;
                index += amount;
                key++;
            }
            state = STATE_FINISH_RESTART;
            delay(1000);
            break;

        }
        case STATE_FINISH_RESTART: {

            state = STATE_INIT;
            break;

        }
    }

}

虛擬類.h

非常小,構造函數只是在字符緩沖區中存儲一個字符串。 這個對象只是一個包裝器。

using namespace std;

class DummyClass {
    private:
        char* _container;

    public:
        DummyClass(){
        }

        DummyClass(string input){
            _container = new char[input.length()];
            strcpy(_container, input.c_str());
        }

        ~DummyClass(){
            delete _container;
            _container = nullptr;
        }

        char* ShowMeWhatYouGot(){
            return _container;
        }
};

編輯:

這是我遇到的一個真正的問題,我不確定為什么它被否決了。 幫幫我,我怎樣才能更清楚? 我不願意縮小代碼,因為它模仿了一個簡單建模的更大程序的許多方面。 我想保留代碼的結構,以防這個錯誤是一個緊急屬性。

始終考慮字符串終止符:

    DummyClass(string input){
        _container = new char[input.length()];
        strcpy(_container, input.c_str());
    }

分配一個太少的字節來保存輸入字符串和終止符,然后將其復制到其中。 最后附加的\\0正在覆蓋某些內容,這很可能是將分配的內存片段成功重新集成到堆中所需的元數據。 我真的很驚訝它沒有崩潰......

它可能不會在每次分配時發生(僅當您溢出到一個新的 8 字節對齊的塊時),但一次就足夠了:)

因此,在經過一些測試之后,我想向評論正確答案的Russ Schultz大聲疾呼。 如果您想正式發布解決方案,我很樂意將其標記為正確。

內存錯誤是由於在未考慮空終止字符的情況下分配 char 緩沖區 _container 引起的,這意味着我正在加載一個太大的字符串。 (不完全確定為什么這會導致錯誤並且不會引發錯誤?)

然而,在另一個網站上,我也收到了這條建議:

 string chunk; for(char i = 0; i < 200; i++){ int index = rand() % alphabet_range; chunk.append(alphabet.substr(index, 1)); // strcat(buffer, alphabet.substring(index, index + 1)); num_chars++; }

這個循環在我看來很可疑。 您依賴於 string append 方法根據需要增加塊,但您知道您將運行該循環 200 次。 為什么不使用字符串保留方法來分配那么多空間呢? 我敢打賭,這會在您追加調用 realloc 的每個新字符時消耗大量內存,從而可能導致內存碎片化。

這最終不是解決方案,但知道它可能很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM