Освобождение памяти

zzzzza
Offline
Зарегистрирован: 18.11.2016

Всем привет!

У меня есть два класса - "PROB" и "BORP".

Я создаю объект класса "PROB", который содержит в себе поле класса "BORP". А потом удаляю его. Между этими действиями я смотрю сколько оперативной памяти свободно. И получается так, что после удаления объекта памяти остается меньше, чем до создания объекта. То есть при удалении объекта освобождается не вся память и я не понимаю почему.

Скетч:

int freeRam ()
 {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
 }



class BORP
 {
  public:
    String nameItem; 
    boolean flagUseSwitchItem;
    byte COUNTSWITCHITEM;
    String *nameSwitchItem = new String[1];
    byte switchPosition;
    byte myIndexSwitch;
    byte STARTX;

  void Init(byte index)
   {
    switch (index)
     {
      case 0:
        myIndexSwitch = index;
        COUNTSWITCHITEM = 2;
        nameSwitchItem = new String[COUNTSWITCHITEM];
        nameSwitchItem[0] = "off";
        nameSwitchItem[1] = "on";
        switchPosition = 0;
        STARTX = 130;
      break;

      case 1:
        myIndexSwitch = index;
        COUNTSWITCHITEM = 3;
        nameSwitchItem = new String[COUNTSWITCHITEM];
        nameSwitchItem[0] = "Low";
        nameSwitchItem[1] = "Med";
        nameSwitchItem[2] = "Hi";
        switchPosition = 0;
        STARTX = 130;
      break;
     }
   }

  ~BORP()
   {
    delete[] nameSwitchItem;
   }
 };


class PROB
 {
  public:
    byte myIndexMenu;
    byte COUNTITEM;
    BORP *masItem = new BORP[1];
    byte cursorPosition;
    byte MAXLINE;
    byte STARTX;
    byte STARTY;
    byte BETWEENY;
    byte STARTPOINTX;
    byte STARTPOINTY;

    PROB(byte index) //Индекс комнаты: 1 - Menu; 2 - Bluetooth; 3 - Memory Options; 4 - Measurements.
     {
      switch (index)
       {
        case 0:
         myIndexMenu = index;
         COUNTITEM = 2;
         masItem = new BORP[COUNTITEM]; //Увеличиваем размер массива.
         masItem[0].nameItem = "Item 0"; masItem[0].flagUseSwitchItem = false;
         masItem[1].nameItem = "Item 1"; masItem[1].flagUseSwitchItem = false;
         cursorPosition = 0;
         MAXLINE = COUNTITEM;
         STARTX = 30;
         STARTY = 10;
         BETWEENY = 10;
         STARTPOINTX = 10;
         STARTPOINTY = 10;
        break;

        case 1:
         myIndexMenu = index;
         COUNTITEM = 5;
         masItem = new BORP[COUNTITEM]; //Увеличиваем размер массива.
         masItem[0].nameItem = "Item 0"; masItem[0].flagUseSwitchItem = true; masItem[0].Init(0); 
         masItem[1].nameItem = "Item 1"; masItem[1].flagUseSwitchItem = false;
         masItem[2].nameItem = "Item 2"; masItem[2].flagUseSwitchItem = false;
         masItem[3].nameItem = "Item 3"; masItem[3].flagUseSwitchItem = true; masItem[3].Init(1); 
         masItem[4].nameItem = "Item 4"; masItem[4].flagUseSwitchItem = false;
         cursorPosition = 0;
         MAXLINE = COUNTITEM;
         STARTX = 30;
         STARTY = 10;
         BETWEENY = 10;
         STARTPOINTX = 10;
         STARTPOINTY = 10;
        break;
       }
     }


    ~PROB()
     {
      delete[] masItem;
     }
 };




void setup()
 {
  Serial.begin(9600);
  while (!Serial) {}
  
  Serial.println(freeRam());
  delay(500);        
  PROB obj(1);
  delay(500);
  Serial.println(freeRam());
  delay(500);
  delete &obj;
  delay(500);
  Serial.println(freeRam());
  delay(500);
 }

void loop() 
 {
  
 }

В мониторе порта отображается следующее:

2328 - осталось памяти до создания объекта
2030 - осталось памяти после создания объекта
2163 - осталось памяти после удаления объекта
 
То есть 165 не освобождается. Почему так происходит?
 
 
sadman41
Offline
Зарегистрирован: 19.10.2016

Что-то я вообще не понял. Указатель на String завели, а потом с какого перепуку он стал массивом строк?  Да еще берете в указатель адрес созданного объекта String в #16, потом в #28 кладете в него адрес другого стринга, а первоначальный объект где повисает?

 

zzzzza
Offline
Зарегистрирован: 18.11.2016

sadman41 пишет:

Что-то я вообще не понял. Указатель на String завели, а потом с какого перепуку он стал массивом строк?  Да еще берете в указатель адрес созданного объекта String в #16, потом в #28 кладете в него адрес другого стринга, а первоначальный объект где повисает?

 

Я думал, что так выделяется динамическая память для массива строк. Просто количество элементов этого массива изначально неизвестно, поэтому я пишу в поле класса:

String *nameSwitchItem = new String[1];

А потом уже увеличиваю его до нужного значения:

nameSwitchItem = new String[COUNTSWITCHITEM];

Как по-другому сделать я не знаю(

sadman41
Offline
Зарегистрирован: 19.10.2016

Динамических массивов, по-моему, в Ардуину не завозили (хотя, могу и ошибаться), поэтому лично я при необходимости динамики пользуюсь дедовским одно- или дву-направленным списком.

zzzzza
Offline
Зарегистрирован: 18.11.2016

sadman41 пишет:

Да еще берете в указатель адрес созданного объекта String в #16, потом в #28 кладете в него адрес другого стринга, а первоначальный объект где повисает?

 

Спасибо за наводку на ошибку. Сделал освобождение памяти перед тем, как задать новый размер (#28, #38, #76, #91) и теперь вся отлично!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

zzzzza пишет:

Спасибо за наводку на ошибку. Сделал освобождение памяти перед тем, как задать новый размер (#28, #38, #76, #91) и теперь вся отлично!

Только непонятно зачем.

Да и не единственная это ошибка. Что у Вас написално в строке 129? Кто Ва учил так освобождать память объекта, созданного не в куче?

Сделайте там нормальное освобождение и просто не запрашивайте ничего в строках 16 и 60. Примерно вот так:

int freeRam ()
 {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
 }



class BORP
 {
  public:
    String nameItem; 
    boolean flagUseSwitchItem;
    byte COUNTSWITCHITEM;
    String *nameSwitchItem; // = new String[1];
    byte switchPosition;
    byte myIndexSwitch;
    byte STARTX;

  void Init(byte index)
   {
    switch (index)
     {
      case 0:
        myIndexSwitch = index;
        COUNTSWITCHITEM = 2;
        nameSwitchItem = new String[COUNTSWITCHITEM];
        nameSwitchItem[0] = "off";
        nameSwitchItem[1] = "on";
        switchPosition = 0;
        STARTX = 130;
      break;

      case 1:
        myIndexSwitch = index;
        COUNTSWITCHITEM = 3;
        nameSwitchItem = new String[COUNTSWITCHITEM];
        nameSwitchItem[0] = "Low";
        nameSwitchItem[1] = "Med";
        nameSwitchItem[2] = "Hi";
        switchPosition = 0;
        STARTX = 130;
      break;
     }
   }

  ~BORP()
   {
    delete[] nameSwitchItem;
   }
 };


class PROB
 {
  public:
    byte myIndexMenu;
    byte COUNTITEM;
    BORP *masItem;// = new BORP[1];
    byte cursorPosition;
    byte MAXLINE;
    byte STARTX;
    byte STARTY;
    byte BETWEENY;
    byte STARTPOINTX;
    byte STARTPOINTY;

    PROB(byte index) //Индекс комнаты: 1 - Menu; 2 - Bluetooth; 3 - Memory Options; 4 - Measurements.
     {
      switch (index)
       {
        case 0:
         myIndexMenu = index;
         COUNTITEM = 2;
         masItem = new BORP[COUNTITEM]; //Увеличиваем размер массива.
         masItem[0].nameItem = "Item 0"; masItem[0].flagUseSwitchItem = false;
         masItem[1].nameItem = "Item 1"; masItem[1].flagUseSwitchItem = false;
         cursorPosition = 0;
         MAXLINE = COUNTITEM;
         STARTX = 30;
         STARTY = 10;
         BETWEENY = 10;
         STARTPOINTX = 10;
         STARTPOINTY = 10;
        break;

        case 1:
         myIndexMenu = index;
         COUNTITEM = 5;
         masItem = new BORP[COUNTITEM]; //Увеличиваем размер массива.
         masItem[0].nameItem = "Item 0"; masItem[0].flagUseSwitchItem = true; masItem[0].Init(0); 
         masItem[1].nameItem = "Item 1"; masItem[1].flagUseSwitchItem = false;
         masItem[2].nameItem = "Item 2"; masItem[2].flagUseSwitchItem = false;
         masItem[3].nameItem = "Item 3"; masItem[3].flagUseSwitchItem = true; masItem[3].Init(1); 
         masItem[4].nameItem = "Item 4"; masItem[4].flagUseSwitchItem = false;
         cursorPosition = 0;
         MAXLINE = COUNTITEM;
         STARTX = 30;
         STARTY = 10;
         BETWEENY = 10;
         STARTPOINTX = 10;
         STARTPOINTY = 10;
        break;
       }
     }


    ~PROB()
     {
      delete[] masItem;
     }
 };




void setup()
 {
  Serial.begin(57600);
  while (!Serial) {}
  
  Serial.println(freeRam());
  delay(500);
  {        
	  PROB obj(1);
	  delay(500);
	  Serial.println(freeRam());
	  delay(500);
  }
  delay(500);
  Serial.println(freeRam());
  delay(500);
 }

void loop() 
 {
  
 }

А вообще, об этой ошибке Вас компилятор предупредил, посто у Вас выключены его предупреждения. Включите и никогда не выключайте.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sadman41 пишет:

Динамических массивов, по-моему, в Ардуину не завозили (хотя, могу и ошибаться)

Таки ошибаетесь

void kaka(const int arraySize) {
	int myArray[arraySize];
	for (int i = 0; i < arraySize; i++) myArray[i] = i + 1;
	for (int i = 0; i < arraySize; i++) {
		Serial.print("myArray[");
		Serial.print(i);
		Serial.print("]=");
		Serial.println(myArray[i]);
	}
}

void setup (void) {
	Serial.begin(57600);
	Serial.println("Fun begins");
	Serial.println("---------------");
	kaka(3);
	Serial.println("---------------");
	kaka(5);
}

void loop(void) {}

Даже const в первой строке необязателен, можно убрать.

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну так это обычный локальный. Я имел в виду такие, как в языках типа пэхэпэ - делай туда push() и не думай о размерности.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Для данного языка и такой за счастье :)

Для "не думать о размерности" есть контейнеры в STL, "but кому это здесь нужно?"

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ЕвгенийП пишет:

Для "не думать о размерности" есть контейнеры в STL

О_О  А чо, так можно было?

zzzzza
Offline
Зарегистрирован: 18.11.2016

ЕвгенийП пишет:

zzzzza пишет:

Спасибо за наводку на ошибку. Сделал освобождение памяти перед тем, как задать новый размер (#28, #38, #76, #91) и теперь вся отлично!

Только непонятно зачем.

Да и не единственная это ошибка. Что у Вас написално в строке 129? Кто Ва учил так освобождать память объекта, созданного не в куче?

Сделайте там нормальное освобождение и просто не запрашивайте ничего в строках 16 и 60. Примерно вот так:

int freeRam ()
 {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
 }



class BORP
 {
  public:
    String nameItem; 
    boolean flagUseSwitchItem;
    byte COUNTSWITCHITEM;
    String *nameSwitchItem; // = new String[1];
    byte switchPosition;
    byte myIndexSwitch;
    byte STARTX;

  void Init(byte index)
   {
    switch (index)
     {
      case 0:
        myIndexSwitch = index;
        COUNTSWITCHITEM = 2;
        nameSwitchItem = new String[COUNTSWITCHITEM];
        nameSwitchItem[0] = "off";
        nameSwitchItem[1] = "on";
        switchPosition = 0;
        STARTX = 130;
      break;

      case 1:
        myIndexSwitch = index;
        COUNTSWITCHITEM = 3;
        nameSwitchItem = new String[COUNTSWITCHITEM];
        nameSwitchItem[0] = "Low";
        nameSwitchItem[1] = "Med";
        nameSwitchItem[2] = "Hi";
        switchPosition = 0;
        STARTX = 130;
      break;
     }
   }

  ~BORP()
   {
    delete[] nameSwitchItem;
   }
 };


class PROB
 {
  public:
    byte myIndexMenu;
    byte COUNTITEM;
    BORP *masItem;// = new BORP[1];
    byte cursorPosition;
    byte MAXLINE;
    byte STARTX;
    byte STARTY;
    byte BETWEENY;
    byte STARTPOINTX;
    byte STARTPOINTY;

    PROB(byte index) //Индекс комнаты: 1 - Menu; 2 - Bluetooth; 3 - Memory Options; 4 - Measurements.
     {
      switch (index)
       {
        case 0:
         myIndexMenu = index;
         COUNTITEM = 2;
         masItem = new BORP[COUNTITEM]; //Увеличиваем размер массива.
         masItem[0].nameItem = "Item 0"; masItem[0].flagUseSwitchItem = false;
         masItem[1].nameItem = "Item 1"; masItem[1].flagUseSwitchItem = false;
         cursorPosition = 0;
         MAXLINE = COUNTITEM;
         STARTX = 30;
         STARTY = 10;
         BETWEENY = 10;
         STARTPOINTX = 10;
         STARTPOINTY = 10;
        break;

        case 1:
         myIndexMenu = index;
         COUNTITEM = 5;
         masItem = new BORP[COUNTITEM]; //Увеличиваем размер массива.
         masItem[0].nameItem = "Item 0"; masItem[0].flagUseSwitchItem = true; masItem[0].Init(0); 
         masItem[1].nameItem = "Item 1"; masItem[1].flagUseSwitchItem = false;
         masItem[2].nameItem = "Item 2"; masItem[2].flagUseSwitchItem = false;
         masItem[3].nameItem = "Item 3"; masItem[3].flagUseSwitchItem = true; masItem[3].Init(1); 
         masItem[4].nameItem = "Item 4"; masItem[4].flagUseSwitchItem = false;
         cursorPosition = 0;
         MAXLINE = COUNTITEM;
         STARTX = 30;
         STARTY = 10;
         BETWEENY = 10;
         STARTPOINTX = 10;
         STARTPOINTY = 10;
        break;
       }
     }


    ~PROB()
     {
      delete[] masItem;
     }
 };




void setup()
 {
  Serial.begin(57600);
  while (!Serial) {}
  
  Serial.println(freeRam());
  delay(500);
  {        
	  PROB obj(1);
	  delay(500);
	  Serial.println(freeRam());
	  delay(500);
  }
  delay(500);
  Serial.println(freeRam());
  delay(500);
 }

void loop() 
 {
  
 }

А вообще, об этой ошибке Вас компилятор предупредил, посто у Вас выключены его предупреждения. Включите и никогда не выключайте.

Спасибо большое за исправления!

Единственное только не понял что делают фигурные скобки без оператора. Они нужны, чтобы просто обозначить блок и лучше был виден кусок кода? В документации не нашел ничего об этом.

zzzzza
Offline
Зарегистрирован: 18.11.2016

Ааа, кажется понял: это что-то типа функции. В теле функции создается объект, а когда из этой функции выходим, объект естественно удаляется, так как внутри функции был создан (локальный).

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

zzzzza пишет:

Ааа, кажется понял: это что-то типа функции. В теле функции создается объект, а когда из этой функции выходим, объект естественно удаляется, так как внутри функции был создан (локальный).

Без обид, но может - лучше для начала таки почитать книжку по С/С++?

zzzzza
Offline
Зарегистрирован: 18.11.2016

DIYMan пишет:

zzzzza пишет:

Ааа, кажется понял: это что-то типа функции. В теле функции создается объект, а когда из этой функции выходим, объект естественно удаляется, так как внутри функции был создан (локальный).

Без обид, но может - лучше для начала таки почитать книжку по С/С++?

Надо бы, но хочу быстренько этот проект сделать. Я понимаю, что и классы у меня организованны криво и не мастер я c++, но потихоньку изучаю, учусь на ошибках.

Ну суть фигурных скобок я примерно правильно описал или нет?

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

zzzzza пишет:

Ну суть фигурных скобок я примерно правильно описал или нет?

Нет. Правильная суть - в книжках по С/С++.

zzzzza
Offline
Зарегистрирован: 18.11.2016

Со скобками у меня почему-то в монитор порта потом ничего не выводится. То есть после скобки ничего не работает, в том числе и вывод свободной памяти.

Serial.println(freeRam());

 

b707
Offline
Зарегистрирован: 26.05.2017

zzzzza пишет:

Ну суть фигурных скобок я примерно правильно описал или нет?

поясните -  где там вообще фигурные скобки без оператора?

zzzzza
Offline
Зарегистрирован: 18.11.2016

b707 пишет:

zzzzza пишет:

Ну суть фигурных скобок я примерно правильно описал или нет?

поясните -  где там вообще фигурные скобки без оператора?

  {       
      PROB obj(1);
      delay(500);
      Serial.println(freeRam());
      delay(500);
  }

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

zzzzza пишет:

Со скобками у меня почему-то в монитор порта потом ничего не выводится. То есть после скобки ничего не работает, в том числе и вывод свободной памяти.

Вы думаете, я выложил не проверяя? Всё у Вас выводится. Возможно надо скорость в мониторе порта поставить такую же как стоит в Serial.begin (у меня не такая, как у Вас была)

zzzzza
Offline
Зарегистрирован: 18.11.2016

ЕвгенийП пишет:

zzzzza пишет:

Со скобками у меня почему-то в монитор порта потом ничего не выводится. То есть после скобки ничего не работает, в том числе и вывод свободной памяти.

Вы думаете, я выложил не проверяя? Всё у Вас выводится. Возможно надо скорость в мониторе порта поставить такую же как стоит в Serial.begin (у меня не такая, как у Вас была)

Для теста полностью ваш код скопировал - все равно не выводит. Может быть у меня старая IDE/компилятор, сейчас посмотрю.

zzzzza
Offline
Зарегистрирован: 18.11.2016

Обновил - то же самое.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

У меня всё выводит. Я вообще-то про скорости писал. Вы их выставили?

zzzzza
Offline
Зарегистрирован: 18.11.2016

ЕвгенийП пишет:

У меня всё выводит. Я вообще-то про скорости писал. Вы их выставили?

Да-да, выставил "57600". Пробовал менять, но ничего. Очень странно, конечно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Взял из поста и попробовал ещё раз (думал, мож при вставке чего поломалось) - всё нормально работает.

В таком случае, Вам в посте #12 всё правильно сказали, рано Вам ещё. Почитайте матчасть, помигайте светодиодами, а то Вы сейчас даже готовый скетч запустить не можете, начинайте с начала, а варианты типа

zzzzza пишет:
но хочу быстренько этот проект сделать.

Обычно не срабатывают.

zzzzza пишет:
Я понимаю,

Ни фига Вы не понимаете, но постарайтесь понять, что начинать надо с нуля, а не сразу со сложных проектов.