Большой объем памяти в функциях Azure - PullRequest
1 голос
/ 18 февраля 2020

Я использую простой код C#. NET Ядро, чтобы посмотреть, как выполняются Azure Функции.

Вариант использования такой: добавьте 10 миллионов значений int в ArrayList как является частью функции Azure и использует триггер времени, установленный на 1 минуту, чтобы вызвать функцию. (Я знаю, что ArrayList устарел и больше не будет использоваться, но я просто использую его, чтобы получить значительный кусок пространства, выделенного в куче). Поэтому код функции C# таков:

using System.Collections;

public static void Run(TimerInfo myTimer, ILogger log)
{
    ArrayList numbers = new ArrayList();
    Random random = new Random(1);
    int noNumbers = 10000000;
    for(int i=0;i<noNumbers;i++) {
        numbers.Add(random.Next(10));
    }

    log.LogInformation($"Created an ArrayList of {numbers.Count} elements");
    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
}

Я проверил настройки платформы и увидел, что это 32-битная версия (я , предполагая , что это относится к. NET Время выполнения ядра 32-разрядное):

enter image description here

Запуск того же примера кода в среде «рабочего стола» с таргетингом. NET Core 3.0 на Windows 10 x64, и использование AppDomain.CurrentDomain.MonitoringTotalAllocatedMemorySize для получения общей выделенной памяти дает следующие результаты (вывод VMMap, затем вывод консоли): enter image description here enter image description here

Значения соответствуют ожидаемым, как показано ниже:

  • Предполагая, что G C возвращает неиспользованные данные до того, как код завершит окончательное распределение памяти, будет иметь значение только конечное состояние. ArrayList реализуется путем выделения массивов object [], длина которых удваивается как число элементов, превышающих текущий; для последнего такого внутреннего массива его длина будет 16 777 216, а каждая ссылка на объект - 4 байта (32-разрядная платформа), что потребляет 67 108 864 байта (ровно 64 МБ); сами упакованные целочисленные значения занимают 10 мил. x 12 байт = 120 000 000 байт (~ 117 МБ), что в сумме дает ~ 181 МБ, что очень похоже на то, что VMMap показывает в столбце «Private»
  • для ArrayList, каждый упакованный int занимает 12 байтов из-за указателя на объект типа (адрес таблицы методов - 4 байта), сохраненного значения (int, которое занимает 4 байта в x86 / x64) и блочного индекса syn c (4 байт). Все эти разбросанные в штучной упаковке целые 114,45 МБ (12 байт / объект х 10 мил объектов). Кроме того, у нас есть сами внутренние массивы, которые выделяются по очереди и занимают 128 МБ (16 байт + 32 байта + 64 байта +… + 32 МБ + 64 МБ). Общий объем составляет 242,45 МБ, что близко к тому, что выводит консольный вывод

Наблюдаемый результат для функции Azure, однако, следующий: график метрик с последующим ручным запуском сама функция): enter image description here

enter image description here

Частные байты, измеренные на графике, намного выше, чем было замечено ранее в VMMap, в то время как число байтов, выделенных за время жизни Функция не соответствует ожидаемому использованию памяти ни для кода x86 (~ 240 МБ), ни для x64 (~ 500 МБ). Это предполагает выполнение кода x86, но с чем-то дополнительным (чьи издержки не пренебрежимо малы), что значительно влияет на приватные байты. Однако наблюдаемое значение приближается к метрике c «частных байтов», измеренной на портале Azure для функции Azure (как «частные байты» приложения «Function», так и «частные байты процесса» приложения Insights являются примерно то же самое).

Каково было бы объяснение количества удвоенных частных байтов в Azure Функции по сравнению с выполнением одного и того же кода на обычной машине?

Почему это так важно? По двум причинам:

  1. Зарядка выполняется за потребление памяти (как один из критериев), так как количество личных байтов указывается как метри c, используемая для вычисления this ( ссылка )
  2. В настоящее время существует ограничение в 1,5 ГБ памяти, используемое функцией Azure; до тех пор, пока использование памяти будет выше, чем можно было бы ожидать, фактический максимальный предел для выделенных типов был бы в результате ниже (например, мне пришлось бы стремиться использовать структуры памяти объемом всего 1,0 ГБ, поскольку остальное - до 1,5 ГБ). необъяснимо используется средой выполнения в Azure Функции)

Соответствующий вопрос GitHub уже открыт здесь .

...