[英]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;
}
}
}
非常小,構造函數只是在字符緩沖區中存儲一個字符串。 這個對象只是一個包裝器。
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.