Утечка оперативной памяти , 0 minheap, как освободить оперативную память из терминала

 

Приветствую всех! 
Столкнулся с проблемой утечки памяти. С каждым циклом в примере их 10, памяти становится все меньше и меньше. Идея простоя. Есть файл с сигналами. Советник каждый день читает его, удаляет файл, редактирует сигналы и записывает снова. Очень странно видеть ошибку с кучей, учитывая, что команд для работы с ней malloc или realloc в mql5 нет.
Профи подскажите, что не так с кодом или другие советы по управлению памятью.


//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

struct SLine{
   string field[];
}; 
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
   {
   PrintMemory();
   for (int i=0;i<10;i++){
      SLine array_signals[];
      ReadFileToArrayAsStruct("Data//Test//signal.txt",array_signals);// читать файл с текущими сигналами
      Print("File Data/Test/signal.txt deleted- ",FileDelete("Data//Test//signal.txt")); // небезопасно в случае прерывания будут удалены сигналы
      Write2ArrayToFile("Data//Test//signal.txt",array_signals,array_signals);// запись массива с новыми и старыми сигналами в файл
      ArrayRemove(array_signals,0,WHOLE_ARRAY);// очистить массив со старыми данными
   }
   PrintMemory(); 
   return(INIT_SUCCEEDED);
   }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  { 
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {   
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+  
void PrintMemory(){
      string strMemUsed       = IntegerToString(TerminalInfoInteger(TERMINAL_MEMORY_USED));
      string strMemAvail      = IntegerToString(TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE));
      string strMemTotal      = IntegerToString(TerminalInfoInteger(TERMINAL_MEMORY_TOTAL));
      string strMemPhys       = IntegerToString(TerminalInfoInteger(TERMINAL_MEMORY_PHYSICAL));
      Print ("\nРазмер памяти, использованной терминалом (агентом), в MB ", strMemUsed, 
      " \nРазмер свободной памяти процесса терминала (агента)в MB ",strMemAvail,
       " \nРазмер памяти, доступной процессу терминала (агента), в MB ", strMemTotal,
      " \nРазмер физической памяти в системе, в MB ",strMemAvail  );
      
      }
//---------------------------------------------------------------------------------------
bool ReadFileToArrayAsStruct(string FileName,SLine & Lines[]){
   ResetLastError();
   int h=FileOpen(FileName,FILE_READ|FILE_ANSI|FILE_CSV|FILE_TXT,";");
   if(h==INVALID_HANDLE){
      int ErrNum=GetLastError();
      printf("Ошибка открытия файла %s # %i",FileName,ErrNum);
      return(false);
   }   
   int lcnt=0; // переменная для подсчета строк 
   int fcnt=0; // переменная для подсчета полей строки    
   while(!FileIsEnding(h)){
      string str=FileReadString(h);
      // новая строка (новый элемент массива структур)
      if(lcnt>=ArraySize(Lines)){ // массив структур полностью заполнен
         ArrayResize(Lines,ArraySize(Lines)+1024); // увеличиваем размер массива на 1024 элемента
      }
      ArrayResize(Lines[lcnt].field,64);// изменяем размер массива в структуре
      Lines[lcnt].field[0]=str; // присваиваем значение первого поля
      // начинаем читать остальные поля в строке
      fcnt=1; // пока занят один элемент в массиве полей
         while(!FileIsLineEnding(h)){ // читаем остальные поля в строке
            str=FileReadString(h);
            if(fcnt>=ArraySize(Lines[lcnt].field)){ // массив полей полностью заполнен
               ArrayResize(Lines[lcnt].field,ArraySize(Lines[lcnt].field)+64); // увеличиваем размер массива на 64 элемента
            }     
            Lines[lcnt].field[fcnt]=str; // присваиваем значение очередного поля
            fcnt++; // увеличиваем счетчик полей
         }
      ArrayResize(Lines[lcnt].field,fcnt); // изменяем размер массива полей в соответствии с фактическим количеством полей
      lcnt++; // увеличиваем счетчик строк
   }
   ArrayResize(Lines,lcnt); // изменяем массив структур (строк) в соответствии с фактическим количеством строк
   FileClose(h);
   return(true);
}  
//-----------------записать массивы в файл-/ если файл был перезапишет первые строчки-------------------------------------
void Write2ArrayToFile(string path_and_name, SLine & Lines[],SLine & Lines2[] ){// передаем путь+имя, массивы структур для записи
   ResetLastError(); 
   int file_handle=FileOpen(path_and_name,FILE_READ|FILE_WRITE|FILE_TXT|FILE_CSV); 
   if(file_handle!=INVALID_HANDLE) 
     { 
     Print("File created ",path_and_name);
     for (int i=0;i<ArraySize(Lines);i++){
            string str=Lines[i].field[0]+";"+Lines[i].field[1]+";"+Lines[i].field[2]+";"+Lines[i].field[3];
            FileWriteString(file_handle,str+"\n",StringLen(str)-1);
      }
      for (int i=0;i<ArraySize(Lines2);i++){
         if(StringLen(Lines2[i].field[0])>1){
            string str=Lines2[i].field[0]+";"+Lines2[i].field[1]+";"+Lines2[i].field[2]+";"+Lines2[i].field[3];
            FileWriteString(file_handle,str+"\n",StringLen(str)-1);  
         } 
      }
   }
FileClose(file_handle); 
}
Файлы:
uozr_odo1qr.JPG  169 kb
signal.txt  4 kb
 

А зачем вы вместо переиспользования массива его пытаетесь удалить и пересоздать в цикле?

   for (int i=0;i<10;i++){
      SLine array_signals[];
      ...
      ArrayRemove(array_signals,0,WHOLE_ARRAY);// очистить массив со старыми данными
   }

Современные менеджеры памяти на управляемых языках не позволяют переиспользовать только что освобожденную память, чтобы избежать "use after free" аттак.

Поэтому не считайте, что работает примитивный malloc/free. Старайтесь максимально переиспользовать ранее выделенные массивы, а не создавать на каждый чих новые массивы.

 

Я пробовал объявлять,  

SLine array_signals[];

как глобальную переменную, но результат такой же. Подумал, может при локальной, должно верно работать.

Большое спасибо за разъяснение!)

Причина обращения: