Как расходуется память при многократном пересоздании массива в цикле? - страница 2

 

запись состояния памяти, примерно такой код , но не проверял, не охота на жесткий диск писать постоянно

#property strict
#property script_show_inputs

#define MemToStrF() StringFormat("%i ; %i ; %i ; %i \n", TerminalInfoInteger(TERMINAL_MEMORY_PHYSICAL),\
          TerminalInfoInteger(TERMINAL_MEMORY_TOTAL), TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE),\
          TerminalInfoInteger(TERMINAL_MEMORY_USED))


#include <Files\FileTxt.mqh>

//+------------------------------------------------------------------+
void OnStart()
{
   func1();
   Print("end");
}

//+------------------------------------------------------------------+
void func1()
{
   CFileTxt f;
   f.Open("f1.csv",FILE_WRITE|FILE_COMMON);
   f.WriteString(" ; m_physical ; m_total ; m_available ; m_used \n");
   f.WriteString("start  " + MemToStrF());
   int i = 1;
   while(i < 1000)
   {
      f.WriteString("in  " + MemToStrF());
      int array[1000];
      array[i] = rand() % i;
      i++;
      f.WriteString("out  " + MemToStrF());
   }
   f.WriteString("end  " + MemToStrF());
}
 
leon_17:

А если вначале цикла на каждой итерации нужен чистый массив (для сбора неких значений на основании неких изменяющихся данных в условии массива)?

То есть, получается, что если внутри цикла, мы объявим динамический массив, и будем ресайзить его на каждой итерации, то память освобождаться не будет, пока не выйдем с цикла? Область видимости здесь тело цикла, я правильно понимаю? Пример кода:

Нет, не получается. Область видимости в этом случае совпадает с границей программы, в которой это безобразие было учинено. 

Вас никто не учил определять переменные в начале программы? MQL этого не требует, на мой взгляд - зря. 

Первая Ваша конструкция ничего не перераспределяет, просто инициализируется массив, а дальше - 4999 операций ни о чём. 

Вторая включает динамический массив, но опять ни о чём. 

Вы цель своих действий можете изложить? Словами. Не обязательно кодом. 

 
Igor Makanu:

замерил скорость:

2020.03.02 22:40:21.269 tst (EURUSD,H1) Test №1 = : loops=10000000 ms=15938

2020.03.02 22:40:37.179 tst (EURUSD,H1) Test №2 = : loops=10000000 ms=15906


т.е. варианты 1 и 2 по скорости выполнения по сути одинаковы

Молодец. Пирожок на полке. 

 
Алексей Тарабанов:

Нет, не получается. Область видимости в этом случае совпадает с границей программы, в которой это безобразие было учинено. 

Вас никто не учил определять переменные в начале программы? MQL этого не требует, на мой взгляд - зря. 

Первая Ваша конструкция ничего не перераспределяет, просто инициализируется массив, а дальше - 4999 операций ни о чём. 

Вторая включает динамический массив, но опять ни о чём. 

Вы цель своих действий можете изложить? Словами. Не обязательно кодом. 

Цель моих действий описана в заголовке темы и в первом ее сообщении.

Код здесь приведен исключительно ради примера, чтобы максимально утрировать интересующий меня вопрос, ясного ответа на который я пока так и не получил. Сравнения скорости различных способов объявления массивов конечно по своему интересны, но не это меня сейчас интересует.

А интересует только то, освобождается ли память в оперативке между итерациями в цикле, если массив каждый раз пересоздавать внутри этого цикла? Неважно зачем так делать и почему код такой бестолковый, просто хочу понять, что происходит с памятью в данной ситуации.  

И да, если при простой инициализации массива никакая физическая память под него не выделяется (в чем я все-таки сомневаюсь), пусть тогда при каждой итерации все ячейки, создаваемого массива еще и заполнятся будут какими либо числами...

 
leon_17:

А интересует только то, освобождается ли память в оперативке между итерациями в цикле, если массив каждый раз пересоздавать внутри этого цикла? Неважно зачем так делать и почему код такой бестолковый, просто хочу понять, что происходит с памятью в данной ситуации.  

я выложил код для записи состояния памяти в файл, проводите эксперименты

код рабочий, я так память при работе с большими строками проверял https://www.mql5.com/ru/forum/1111/page2646#comment_14973065


но думаю, что статически распределенные массивы вообще не изменяют состояние памяти MQL-программы, не важно где такой массив находится в глобальной или локальной области видимости, проверить это скорее всего можно объявив несколько статически распределенных массивов и вывести в принт доступную память, затем  закомментировать часть массивов и опять в принты..... но нужно учитывать, что компилятор очень хорошо определяет не используемый код и выбросит эти части кода из программы - включая пустые объявления массивов - т.е. как в моих примера присваивайте элементам массива хоть что нибудь, но не константу - это тоже может быть компилятор удалит ;)

 
leon_17:

Что происходит с памятью, если использовать вот такой код:

int i=0;
while(i<5000){
   i++;
   int array[1000];
}

Ответ: ни чего с памятью тут не происходит. Память физически не выделяется и не освобождается.
Это стек, память под него выделяется до начала выполнения пользовательского кода и освобождается после.
Под стек выделяется память определенного размера - детали #property stacksize
Для скрипта максимальный размер стека - 64МБ, если локальные переменные требуют больше - терминал не запустит скрипт на выполнение MT5 (build 2345) и выдаст ошибку:

Service cannot be started. Stack size of 64MB exceeded. Reduce the memory occupied by local variables


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

leon_17:

1) Созданный на предыдущей итерации массив выгружается с памяти или для нового массива просто выделяется новая память?
2) Теоретически мы можем ее перезаполнить?
3) И это какая используется память: RAM?

1) "выгружается с памяти" - это конкретный термин, означающий копирование информации содержащиеся в памяти в другое место, например на диск.
В данном контексте он не уместен, возможно имелось ввиду "освобождается ли физически память под  переменную массива", на данный вопрос ответ был предоставлен выше.

2) Перезаполнить стековую память можно просто вызвав функцию с бесконечной рекурсией.
В стеке сохраняется адрес возврата при выходе из функции - это адрес инструкции, которая будет выполнятся после выхода из функции.
В бесконечной рекурсии адрес возврата бесконечно записывается на стек, пока его не переполнит. Запущенная программа вылетает с ошибкой stack overflow.

3) "И это какая используется память: RAM?" Вы спрашиваете масло масляное.
Для начала изучите чем отличается стековая память (stack memory) от памяти кучи (heap memory) в С++ тогда и приходите. 



 
leon_17:

А если вначале цикла на каждой итерации нужен чистый массив (для сбора неких значений на основании неких изменяющихся данных в условии массива)?

///

Просто очистить его и все - ArrayInitialize()

 
Igor Makanu:

замерил скорость:

2020.03.02 22:40:21.269 tst (EURUSD,H1) Test №1 = : loops=10000000 ms=15938

2020.03.02 22:40:37.179 tst (EURUSD,H1) Test №2 = : loops=10000000 ms=15906


т.е. варианты 1 и 2 по скорости выполнения по сути одинаковы

Потому что компилятор оптимизирует код, и в итоге сравниается скорость работы двух одинаковых пустых циклов. Потому что результаты вычислений нигде не используются.

 
Dmitry Fedoseev:

Потому что компилятороптимизирует код и по сути в итоге сравниается скорость работы двух одинаковых пустых циклов. Потому что результаты вычисленй нигде не используются.

Ну не пустых же, обращение к массиву и деление есть) 

Сергей выше разжевал же детально, если даже будут вычисления тяжелые - скорость будет одинаковая.Потому что массив "выделяется" в стеке, и лишних операций не происходит.

Интересен нюанс, если внутри цикла другие циклы по условию, если определять внутри них переменные и если нет - разница будет ли, т.е. сколько времени занимает сдвиг указателя стека если он есть,

для внутреннего цикла (который ничего не возвращает ведь) не должно быть потери, но не факт.

 
Aleksey Mavrin:

Ну не пустых же, обращение к массиву и деление есть) 

Сергей выше разжевал же детально, если даже будут вычисления тяжелые - скорость будет одинаковая.Потому что массив "выделяется" в стеке, и лишних операций не происходит.

Интересен нюанс, если внутри цикла другие циклы по условию, если определять внутри них переменные и если нет - разница будет ли, т.е. сколько времени занимает сдвиг указателя стека если он есть,

для внутреннего цикла (который ничего не возвращает ведь) не должно быть потери, но не факт.

Но итоги нигде дальше не исползуются. Компилятор это выкидывает. 

И что, если кто-то выучил слова "стек" и "куча", сильно умный от этого стал?

Угу, ничего не выделяется не осовбождается... а если рекурсивный вызов?

Единственное преимущество с++ программистов пред всем осталным миром в томю, что они почему-то непоколебимо уверены в своей неу-нной опупенности. 

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