2016-12-21 13 views
0

こんにちは、私は新しいArduinoプロジェクト1.6.10 IDE verを開始しています。私はクラスベースの構造を使用するときにメモリリークのいくつかの問題に直面している。Arduinoクラス階層、文字列とメモリリーク

私はコードを最初に投稿してから、メモリリークが発生したときにその場所を指します。

mainSketchFile。問題はState.hiであるように思わ

#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()); 
} 

はコメントでポイントをマークし

#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 

メモリリーク特性文字列STA tusNameのコメントが外されています

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 

ありがとうございました。あなたが私を助けてくれることを願います。

+0

どのくらいの空きメモリが利用可能であるかは、メモリリークを検出するための良い方法ではありません。理由は、OSがチャンク内のメモリを提供するからです。一部のメンバーを追加するには別のチャンクが必要になる可能性があります。これは無料のRAM番号を説明します。 – Ripi2

+0

名前のゲッターとセッターはどこですか? – NonCreature0714

+0

statusNameのGetteとsetterは問題に影響を与えません(私はそれをテストしました)。私はコードを短くしてより速く読むことができるように、ここに投稿するようにそれらを削除しました。 – groot

答えて

1

これがメインで私の結果である

#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 

..私はあなたのコードに基づいて実装を投稿

、デストラクタの問題のように思える:OSをお願い

... 

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 

... 
+0

はtxで動作します。私は数日でそれに乗っていた。明けましておめでとうございます。 – groot

+0

あなたにも新しい年があります。 –

0

免責事項:私はこれをコメントではなく回答として投稿したかったのですが、私の意見では問題は解決していませんが、アドバイスがあるからです。それから私はいくつかのコードブロックが必要だったので、私は答えの機能が必要でした。

さて、あなたのコードの私見は、いくつかの改善が必要である(または多分それはあなたがそれを縮小という理由だけだが、とにかく私はあなたのためにそれらを投稿します)

  1. ヘッダファイルに関数の実装を入れないでください。 cppファイルを使用して関数の実装を格納し、ヘッダファイルにプロトタイプを格納します
  2. 継承の目的は、すでに共通しているコードの大部分を再利用することです。したがって、さまざまな変数を持つことは意味がありません。別々に宣言するほうがはるかに優れています。
  3. あなたはこのようにそれを使用することができます。例えば

:あなたは数の値を変更する必要はありません(とあなたが本当の変数を必要としない)場合

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

または、

次に、割り当て解除に小さな問題があります。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に達して印刷されない場合は、ライブラリの問題です。一方、プログラムが文字列の印刷を停止すると、それはリークです。

1つのサイドノート:小さなマイコンにメモリが限られているため、割り当てや割り当て解除を頻繁に実行させるのは良い習慣ではありません。本当のリークがあるかもしれない場合は、もっと調査する必要があるかもしれないので、テストを行います。しかし、あなたのアプリケーションでは、オブジェクトの2つのインスタンスを永久に割り当てることを考え、前に渡した値派生クラスの唯一のカップルが存在する場合)、次のように:

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

FINAL注:答えを改訂私はあなたのchangeStatus機能ではなくvoidvoid *を返すことがわかりました。あなたは間違いなくそれを修正する必要があり、MAYBEのものは修正されます(実際には何もせずにポインタを戻しています)。しかし、私はそれについては分かりません。

+0

あなたの貢献のためのTx。あなたはコードが非常に基本的であることを暗示していたので、読者が問題を迅速に理解し、問題を引き起こす方法にのみ重点を置くか、バグを避けるために不可欠なものはすべて削除しました。 – groot

+0

あなたはコードが非常に基本的であることを暗示していたので、読者が問題を迅速に理解し、すべての二次的な問題やバグを避けるために不可欠なものはすべて削除しました。不足しているセッターとゲッター。私はあなたの議論を非常に興味深いと思っており、私はそれを試してみるつもりです。あなたは関数のエラーで、無駄なポインタを返すことに関して正しくありました。残念ながら私はそれを削除しましたが、メモリリークはまだ存在しています。 – groot

+0

喜んで私は少なくともいくつかのヒントを与えることができます..私はあなたが問題を見つけることを望む(そして、私は解決策について興味があるので、それを共有するために戻ってくる)。ちなみに、あなたはその文字列をdinamicallyに割り当てて、アイテムデストラクタで削除しようとすることができます – frarugi87

関連する問題