[英]Arduino class hierarchy, Strings and memory leak
下午好,我要開始一個新的Arduino Project 1.6.10 IDE版本。 但是當我使用基於類的結構時遇到內存泄漏的一些問題。
我先發布代碼,然后在內存泄漏似乎出現的時候指出該位置。
mainSketchFile。
#include <Ethernet.h>
#include <MemoryFree.h>
#include "Constants.h"
#include "State.h"
StateFactory CurrentStateFactory;
void setup() {
pinMode(BUZZER,OUTPUT);
Serial.begin(9600);
Serial.println("START");
delay(1000);
}
void loop() {
Serial.print(F("Free RAM = "));
Serial.println(freeMemory(), DEC); // print how much RAM is available.
CurrentStateFactory.changeStatus(1);
Serial.println(CurrentStateFactory.getCurrentState()->getNumber());
CurrentStateFactory.changeStatus(2);
Serial.println(CurrentStateFactory.getCurrentState()->getNumber());
}
問題似乎出在State.hi在評論中指出了重點
#ifndef State_h
#define State_h
/////////////////// STATE/////////////////////////
class MachineState{
public:
virtual int getNumber();
protected:
};
/////////////////////ACTIVE FULL/////////////////////////////////
class ActiveFull : public MachineState
{
public:
ActiveFull();
virtual int getNumber();
private:
String statusName; //<----- PROBLRM SEEMS TO BE HERE WHEN COMMENTED NO MEMORY LEAK APPEN
int number;
};
ActiveFull::ActiveFull(){
this->number=1;
};
int ActiveFull::getNumber(){
return this->number;
}
////////////////////////////// ACTIVE EMPTY ////////////////////
class ActiveEmpty : public MachineState
{
public:
ActiveEmpty();
virtual int getNumber();
protected:
String statusName;//<----- PROBLRM SEEMS TO BE HERE WHEN COMMENTED NO MEMORY LEAK APPEN
int number;
};
ActiveEmpty::ActiveEmpty(){
this->number=2;
};
int ActiveEmpty::getNumber(){
return this->number;
}
//////////////////FACTORY/////////////////////////////
class StateFactory{
private:
MachineState *currentState;
public:
StateFactory();
void *changeStatus(int choice); // factory
MachineState *getCurrentState();
};
StateFactory::StateFactory(){
MachineState *var1=new ActiveFull();
this->currentState=var1;
}
MachineState *StateFactory::getCurrentState(){
return this->currentState;
}
void *StateFactory::changeStatus(int choice)
{
delete this->currentState; // to prevent memory leak
if (choice == 1){
MachineState *var1=new ActiveFull();
this->currentState=var1;
}
else if (choice == 2){
MachineState *var1=new ActiveEmpty;
this->currentState=var1;
}
else{
MachineState *var1=new ActiveEmpty;
this->currentState=var1;
}
}
#endif
我使用庫來跟蹤內存使用情況,這是草圖的輸出:
沒有內存泄漏(字符串statusName已注釋)
Free RAM = 7897
1
2
Free RAM = 7897
1
2
Free RAM = 7897
1
2
Free RAM = 7897
1
2
Free RAM = 7897
1
2
Free RAM = 7897
1
2
Free RAM = 7897
1
2
Free RAM = 7897
1
2
Free RAM = 7897
1
2
屬性字符串statusName取消注釋時發生內存泄漏
Free RAM = 6567
1
2
Free RAM = 6559
1
2
Free RAM = 6551
1
2
Free RAM = 6543
1
2
Free RAM = 6535
1
2
Free RAM = 6527
1
2
感謝您的寶貴時間。 希望您能夠幫助我。
似乎是一個破壞者的問題,
我根據您的代碼發布了一個實現。
#ifndef State_h
#define State_h
/* MachineState Class */
class MachineState{
public:
virtual void test() = 0;
MachineState(){
number = 0;
statusName = "NULL";
}
virtual ~MachineState(){
Serial.println("Destroy base");
}
void setNumber(int n){
number = n;
}
void setStatusName(String some){
statusName = some;
}
String getStatusName(){
return statusName;
}
int getNumber(){
return number;
}
virtual void print()const{
Serial.println("Class MS");
}
protected:
String statusName;
int number;
};
/* ActiveFull Class */
class ActiveFull : public MachineState{
public:
ActiveFull(){
x = "Class AF";
setNumber(1);
}
void print()const{
Serial.println("Class AF");
}
void test(){}
~ActiveFull(){
Serial.println("Destroy AF");
}
private:
String x;
};
/* ActiveEmpty Class */
class ActiveEmpty : public MachineState
{
public:
void print()const{
Serial.println("Class EE");
}
ActiveEmpty(){
x = "Class EE";
setNumber(2);
}
void test(){}
~ActiveEmpty(){
Serial.println("Destroy EE");
}
private:
String x;
};
/* StateFactory Class */
class StateFactory{
private:
MachineState *currentState;
public:
StateFactory();
~StateFactory(){
Serial.println("Ho distrutto StateFactory");
}
void changeStatus(int choice); // factory
MachineState *getCurrentState();
};
StateFactory::StateFactory(){
this->currentState=new ActiveFull();
}
MachineState *StateFactory::getCurrentState(){
return this->currentState;
}
void StateFactory::changeStatus(int choice){
if(this->currenState)
delete this->currentState;
if (choice == 1){
currentState = new ActiveFull();
}
else if (choice == 2){
currentState = new ActiveEmpty();
}
else{
currentState = new ActiveEmpty();
}
}
#endif
這是我的主要結果:
...
2
Class EE
Free RAM = 7751
Destroy EE
Destroy base
1
Class AF
Destroy AF
Destroy base
2
Class EE
Free RAM = 7751
Destroy EE
Destroy base
1
Class AF
Destroy AF
Destroy base
...
免責聲明:我想將其發布為評論,而不是答案,因為我認為這不能解決問題,而只能提供建議。 然后,我需要一些代碼塊,因此我需要答案功能。
好吧,您的代碼恕我直言需要一些改進(或者也許只是因為您減少了它,但是無論如何我都會為您發布它們)
例如,您可以像這樣使用它:
/* File State.h */
class MachineState{
public:
int getNumber();
protected:
String statusName;
int number;
};
/////////////////////ACTIVE FULL/////////////////////////////////
class ActiveFull : public MachineState
{
public:
ActiveFull();
};
////////////////////////////// ACTIVE EMPTY ////////////////////
class ActiveEmpty : public MachineState
{
public:
ActiveEmpty();
};
/* File State.cpp */
int MachineState::getNumber(){
return this->number;
}
ActiveEmpty::ActiveEmpty(){
this->number=1;
};
ActiveEmpty::ActiveEmpty(){
this->number=2;
};
或者,如果您不必更改number的值(因此您不需要實數變量)
/* File State.h */
class MachineState{
public:
virtual int getNumber() = 0;
protected:
String statusName;
};
/////////////////////ACTIVE FULL/////////////////////////////////
class ActiveFull : public MachineState
{
public:
virtual int getNumber();
};
////////////////////////////// ACTIVE EMPTY ////////////////////
class ActiveEmpty : public MachineState
{
public:
virtual int getNumber();
};
/* File State.cpp */
int ActiveEmpty::getNumber(){
return 1;
};
int ActiveEmpty::getNumber(){
return 2;
};
然后,釋放存在一個小問題:如果new
失敗,則在下一個delete
會遇到問題。 為了解決這個問題,您可以做類似的事情(而且我也縮短了您的代碼)
void *StateFactory::changeStatus(int choice)
{
if (this->currentState) // If it was correctly allocated
delete this->currentState; // to prevent memory leak
switch (choice)
{
case 1:
this->currentState = new ActiveFull();
break;
case 2: // case 2 can be removed since it is identical to default
this->currentState = new ActiveEmpty();
break;
default:
this->currentState = new ActiveEmpty();
break;
}
}
就是說...好吧,我會這樣修改循環:
void printCurrentStateNumber()
{
if (CurrentStateFactory.getCurrentState())
Serial.println(CurrentStateFactory.getCurrentState()->getNumber());
else
Serial.println("No more memory");
}
void loop() {
Serial.print(F("Free RAM = "));
Serial.println(freeMemory(), DEC); // print how much RAM is available.
CurrentStateFactory.changeStatus(1);
printCurrentStateNumber();
CurrentStateFactory.changeStatus(2);
printCurrentStateNumber();
}
這是為了測試狀態是否成功創建。
至於您的顯式問題,我不知道庫函數如何工作。 在開始理解為什么會有這種泄漏之前,我會先弄清楚這是否真的是泄漏。 因此,請啟動修改后的程序(在刪除之前先進行測試,然后打印不再存儲的字符串),然后運行該程序,直到庫告知您內存不足。 如果它穩定或達到0而沒有打印出來,那就是磁帶庫問題。 另一方面,如果程序停止打印字符串,則可能是泄漏。
一個旁注:讓小型微控制器過於頻繁地執行分配和釋放操作不是一個好習慣,因為它的內存有限。 進行測試,因為如果存在真正的泄漏,也許應該對其進行更多的調查,但是對於您的應用程序,我建議您考慮永久分配該對象的兩個實例,然后根據之前傳遞的值使用它們-顯然如果只有幾個派生類),如下所示:
/* In the header file */
#define NUM_OF_STATES 2
class StateFactory{
private:
MachineState states[NUM_OF_STATES];
public:
StateFactory();
void changeStatus(int choice); // factory
MachineState *getCurrentState();
private:
int currentIdx;
};
/* In the source file */
StateFactory::StateFactory()
{
states[0] = new ActiveFull();
states[1] = new ActiveEmpty();
this->currentIdx = 0;
}
MachineState *StateFactory::getCurrentState(){
return states[this->currentIdx];
}
void StateFactory::changeStatus(int choice)
{
switch (choice)
{
case 1:
this->currentIdx = 0;
break;
case 2: // case 2 can be removed since it is identical to default
this->currentIdx = 1;
break;
default:
this->currentIdx = 1;
break;
}
}
最后的提示:修改答案我發現您的changeStatus
函數返回一個void *
而不是void
。 您絕對應該解決此問題,並且可能所有事情都會得到解決(實際上,您返回的是指針而不是沒有指針)。 但是我不確定。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.