Работающие приложения вычисляют данные, какая память

Обновлено: 02.07.2024

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

Несмотря на то, что вы можете в любое время собирать снимки памяти с помощью инструмента «Использование памяти», вы можете использовать отладчик Visual Studio, чтобы контролировать выполнение приложения при исследовании проблем с производительностью. Установка точек останова, пошаговое выполнение, Прервать все и другие действия отладчика могут помочь вам сосредоточить исследования производительности на наиболее релевантных путях кода. Выполнение этих действий во время работы приложения может устранить шум в коде, который вас не интересует, и значительно сократить время, необходимое для диагностики проблемы.

В этом руководстве вы:

  • Создание снимков памяти
  • Анализ данных об использовании памяти

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

Поддержка настраиваемого распределителя. Собственный профилировщик памяти работает, собирая данные о событиях ETW выделения, созданные во время выполнения. Распределители в CRT и Windows SDK аннотированы на исходном уровне, чтобы можно было зафиксировать данные об их распределении. Если вы пишете свои собственные распределители, то любые функции, возвращающие указатель на недавно выделенную память кучи, могут быть украшены __declspec(allocator), как показано в этом примере для myMalloc:

__declspec(распределитель) void* myMalloc(size_t size)

Сбор данных об использовании памяти

Откройте проект, который вы хотите отлаживать, в Visual Studio и установите точку останова в своем приложении в точке, с которой вы хотите начать проверку использования памяти.

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

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

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

Окно «Средства диагностики» появляется автоматически, если вы не выключили его. Чтобы снова открыть это окно, нажмите «Отладка» > «Windows» > «Показать инструменты диагностики».

Выберите «Использование памяти» с помощью параметра «Выбор инструментов» на панели инструментов.

 Показать средства диагностики

Нажмите "Отладка"/"Начать отладку" (или "Пуск" на панели инструментов или F5).

Когда приложение завершит загрузку, появится сводка инструментов диагностики.

 Вкладка

Поскольку сбор данных о памяти может повлиять на производительность отладки ваших собственных или смешанных приложений, моментальные снимки памяти по умолчанию отключены. Чтобы включить моментальные снимки в собственных или смешанных приложениях, запустите сеанс отладки (сочетание клавиш: F5). Когда появится окно «Средства диагностики», выберите вкладку «Использование памяти», а затем выберите «Профилирование кучи».

Включить моментальные снимки

Остановить (сочетание клавиш: Shift+F5) и перезапустить отладку.

Чтобы сделать снимок в начале сеанса отладки, выберите «Создать снимок» на сводной панели инструментов «Использование памяти». (Здесь также может помочь установить точку останова.)

Сделать снимок

Чтобы создать основу для сравнения памяти, рассмотрите возможность создания моментального снимка в начале сеанса отладки.

Запустите сценарий, который приведет к срабатыванию первой точки останова.

Когда отладчик остановлен в первой точке останова, выберите «Создать снимок» на сводной панели инструментов «Использование памяти».

Нажмите F5, чтобы запустить приложение до второй точки останова.

Теперь сделайте еще один снимок.

С этого момента вы можете приступить к анализу данных.

Анализ данных об использовании памяти

В строках сводной таблицы "Использование памяти" перечислены снимки, сделанные во время сеанса отладки, и приведены ссылки на более подробные представления.

Сводная таблица памяти

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

Чтобы проанализировать использование памяти, нажмите на одну из ссылок, которая откроет подробный отчет об использовании памяти:

Увеличение использования памяти

  • Чтобы просмотреть сведения о различиях между текущим снимком и предыдущим снимком, выберите ссылку изменения слева от стрелки (). Красная стрелка указывает на увеличение использования памяти, а зеленая стрелка на уменьшение.

Чтобы быстрее выявлять проблемы с памятью, отчеты о различиях сортируются по типам объектов, общее количество которых увеличилось больше всего (нажмите на ссылку изменения в столбце "Объекты (Diff)") или которые больше всего увеличили общий размер кучи (нажмите кнопку изменить ссылку в столбце Размер кучи (Diff)).

Чтобы просмотреть сведения только о выбранном снимке, щелкните ссылку без изменений.

Отчет появится в отдельном окне.

Отчеты по управляемым типам

Выберите текущую ссылку на ячейку «Объекты» (Diff) или «Выделения (Diff)» в сводной таблице «Использование памяти».

Отчет управляемого типа отладчика — пути к корню

В верхней панели отображается количество и размер типов в моментальном снимке, включая размер всех объектов, на которые ссылается тип (включая размер).

В дереве объектов, на которые есть ссылки, отображаются ссылки, относящиеся к типу, выбранному на верхней панели.

Представление отчета об управляемых объектах, на которые имеются ссылки

Чтобы отобразить экземпляры выбранного типа на верхней панели, выберите значок.

Скриншот представления

В представлении «Экземпляры» на верхней панели отображаются экземпляры выбранного объекта в моментальном снимке. На панели «Пути к корню и объектам, на которые есть ссылки» отображаются объекты, которые ссылаются на выбранный экземпляр, и типы, на которые ссылается выбранный экземпляр. Когда отладчик остановлен в точке, где был сделан снимок, вы можете навести указатель мыши на ячейку «Значение», чтобы отобразить значения объекта во всплывающей подсказке.

Отчеты собственного типа

Выберите текущую ссылку на ячейку "Распределение" (Diff) или "Размер кучи" (Diff) в сводной таблице "Использование памяти" в окне "Средства диагностики".

Просмотр собственного типа

В представлении «Типы» отображается количество и размер типов в снимке.

Выберите значок экземпляров ( ) выбранного типа, чтобы отобразить информацию об объектах выбранного типа в снимке.

В представлении «Экземпляры» отображаются все экземпляры выбранного типа. При выборе экземпляра отображается стек вызовов, который привел к созданию экземпляра, на панели стека вызовов распределения.

Скриншот представления

Выберите «Просмотр стеков» в списке «Режим просмотра», чтобы просмотреть стек распределения для выбранного типа.

Просмотр стеков

Отчеты об изменениях

Выберите ссылку изменения в ячейке сводной таблицы на вкладке "Использование памяти" в окне "Средства диагностики".

Выберите отчет об изменениях

Выберите снимок в списке «Сравнить с» управляемого или собственного отчета.

Выберите снимок из списка

Отчет об изменениях добавляет в базовый отчет столбцы (помеченные знаком (Diff)) и показывающие разницу между значением базового снимка и сравнительным снимком. Вот как может выглядеть отчет о различиях в представлении нативного типа:

Просмотр различий собственных типов< бр />

Блоги и видео

Дальнейшие шаги

Из этого руководства вы узнали, как собирать и анализировать данные об использовании памяти. Если вы уже ознакомились с профилировщиком, возможно, вы захотите узнать, как анализировать загрузку ЦП в ваших приложениях.

Модули памяти Kingston

ОЗУ (оперативное запоминающее устройство) обеспечивает быстрый доступ и временное хранение данных на компьютерах. Оперативная память находится между процессором и постоянным хранилищем данных, например жестким диском или твердотельным накопителем. Когда компьютер включен, процессор запрашивает данные (например, операционную систему) с жесткого диска/твердотельного накопителя и загружает их в оперативную память. Оперативная память в тысячи раз быстрее, чем даже у самых быстрых твердотельных накопителей, поэтому наличие большего объема ОЗУ для хранения приложений и данных рядом с процессором помогает сделать вычисления быстрыми и эффективными.

Сколько у меня оперативной памяти?

Если вы используете ПК с ОС Windows
  1. Найдите значок "Компьютер" в меню "Пуск".
  2. Щелкните правой кнопкой мыши значок "Компьютер" и выберите "Свойства" в меню.
  3. В разделе "Система" и под моделью процессора отображается объем установленной памяти, измеряемый в МБ (мегабайтах) или ГБ (гигабайтах).
Если вы используете систему MAC
  1. Откройте меню Apple и нажмите «Об этом Mac».
  2. Выберите «Отчет о системе», чтобы отобразить экран «Информация о системе».
  3. Нажмите «Память» в разделе «Оборудование».

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

Сколько оперативной памяти мне нужно?

Базовый объем оперативной памяти компьютера составляет 4 ГБ; как правило, он выполняет свою работу — просто не ожидайте, что несколько приложений будут открыты одновременно, не влияя на производительность. Для конфигурации среднего уровня может потребоваться в два раза больше, а для игровых систем и рабочих станций высокого класса требуется до 16 ГБ или 32 ГБ.

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

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

  • Если вам не хватает памяти, полезно знать, нужно ли вам просто обновить свой ноутбук с 8 ГБ до 16 ГБ ОЗУ или вашему процессу требуется 200 ГБ ОЗУ, и пришло время провести некоторую оптимизацию.
  • Если вы выполняете параллельные вычисления, вам нужно знать, сколько памяти занимает каждая отдельная задача, чтобы знать, сколько задач нужно выполнять параллельно.
  • Если вы масштабируетесь до нескольких запусков, вам необходимо оценить затраты на оборудование или облачные ресурсы.

В первом случае вы не можете измерить пиковое использование памяти, потому что вашему процессу не хватает памяти. А в остальных случаях вы можете работать с разными входными данными в разное время, что приводит к разным требованиям к памяти.

Что вам действительно нужно, так это модель того, сколько памяти потребуется вашей программе для разных размеров ввода. Давайте посмотрим, как вы можете это сделать.

Измерение пикового использования памяти

Когда вы изучаете требования к памяти, в первом приближении значение имеет пиковое использование памяти. Если ваш процесс использует 100 МБ ОЗУ в 99,9% случаев и 8 ГБ ОЗУ в 0,1% случаев, вы все равно должны обеспечить наличие 8 ГБ ОЗУ. В отличие от ЦП, если у вас закончится память, ваша программа не будет работать медленнее — она рухнет.

Как вы измеряете пиковую память процесса?

В Linux и macOS вы можете использовать ресурс стандартного модуля библиотеки Python:

В Linux это будет измеряться в КиБ, в macOS — в байтах, поэтому, если ваш код работает на обоих, вам нужно сделать его согласованным.

В Windows вы можете использовать библиотеку psutil:

Это вернет пиковое использование памяти в байтах.

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

Оценка и моделирование пикового использования памяти

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

Идея состоит в том, чтобы измерить использование памяти для серии входных данных разного размера. Затем вы можете экстраполировать использование памяти для разных и/или больших наборов данных в зависимости от размера входных данных.

Давайте рассмотрим пример, программу, которая регистрирует изображения, выясняя, что два похожих изображения смещены друг относительно друга по координатам X, Y. В целом, мы ожидаем, что использование памяти будет масштабироваться вместе с размером изображения, поэтому мы настроим программу так, чтобы она поддерживала изображения разных размеров, и по завершении она будет сообщать о пиковом использовании памяти:

Затем мы можем запустить эту программу с несколькими размерами входного изображения:

Теперь у нас есть следующие цифры использования памяти:

Килопиксели Пиковая память в МиБ
256 116
1024 176
2304 277
4096 417

Моделирование использования памяти

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

Диаграмма, демонстрирующая линейный рост использования памяти

Учитывая, что использование памяти кажется линейным с входными данными, мы можем построить линейную модель с помощью NumPy:

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

Практические соображения

Пиковый объем резидентной памяти не совпадает с пиковым использованием памяти

Выше мы измеряем объем памяти, хранящийся в ОЗУ при пиковых нагрузках. Если ваша программа начинает подкачку, выгружая память на диск, пиковое использование памяти может быть выше, чем резидентной памяти.

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

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

Добавить фактор выдумки

Хотя модель часто дает разумную оценку, не думайте, что она абсолютно верна. Вы можете добавить к оценке еще 10 % или больше в качестве фактора подтасовки, поскольку реальное использование памяти может несколько отличаться.

Другими словами, если модель говорит, что вам нужно 800 МБ ОЗУ, убедитесь, что свободно 900 МБ.

Использование памяти может быть нелинейным

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

Когда следует оптимизировать использование памяти

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

Большие наборы данных в сочетании с кривой требований к памяти, превышающей линейную, — плохое сочетание: как минимум вам понадобится некоторая форма пакетной обработки, но изменения в ваших алгоритмах также могут быть хорошей идеей.

Узнайте еще больше о способах сокращения использования памяти — прочтите остальную часть руководства по наборам данных, превышающим объем памяти, для Python.

Тратить время и деньги на процессы, использующие слишком много памяти?

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

Вам нужен инструмент, который точно подскажет, на чем следует сосредоточить усилия по оптимизации, инструмент, разработанный для специалистов по обработке и анализу данных. Узнайте, чем может помочь профилировщик памяти Fil.

Как вы обрабатываете большие наборы данных с ограниченным объемом памяти?

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

Кроме того, примерно каждую неделю вы будете получать новые статьи, в которых рассказывается, как обрабатывать большие данные и, в более общем плане, улучшать свои навыки разработки программного обеспечения, от тестирования до упаковки и повышения производительности:

Эта статья представляет собой набор указателей на измерение производительности Java. Он описывает, как работает память в целом и как Java использует кучу и стек. В статье описано, как установить доступную память для Java. Затем обсуждается, как получить время выполнения и потребление памяти приложением Java.

1. Факторы эффективности

Важные факторы, влияющие на производительность программы Java, можно разделить на две основные части:

Потребление памяти программой Java

Общее время выполнения программы

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

Средний ЦП может выполнять примерно 1 миллиард (10^9) операций в секунду.

В этой статье параллелизм не рассматривается. Если вы хотите прочитать о параллелизме/многопоточности, см. статью Параллелизм/многопоточность в Java

2. Обработка памяти в Java

Java использует две области памяти. куча и стек. Мы начнем с краткого обзора памяти в целом на компьютере. Затем объясняются куча и стек Java.

2.1. Собственная память

Собственная память — это память, доступная для процесса, например. Java-процесс. Собственная память управляется операционной системой (ОС) и основана на физической памяти и других физических устройствах, например. диски, флэш-память и т. д.

Процессор (ЦП) компьютера вычисляет инструкции для выполнения и сохраняет результаты вычислений в регистрах. Эти регистры представляют собой элементы быстрой памяти, в которых хранится результат ЦП. Процессор может получить доступ к обычной памяти через шину памяти. Объем памяти, к которому может получить доступ ЦП, зависит от размера физического адреса, который ЦП использует для идентификации физической памяти. 16-битный адрес может получить доступ к 2^16 (= 65,536) ячейкам памяти. 32-битный адрес может получить доступ к 2^32 (= 4.294.967.296) ячейкам памяти. Если каждая область памяти состоит из 8 байтов, то 16-разрядная система может получить доступ к 64 КБ памяти, а 32-разрядная система может получить доступ к 4 ГБ памяти.

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

Текущие 32-разрядные системы используют расширение (Physical Address Extension (PAE)), которое расширяет физическое пространство до 36-разрядной операционной системы. Это позволяет ОС получить доступ к 64 ГБ. Затем ОС использует виртуальную память, чтобы предоставить отдельному процессу 4 ГБ памяти. Даже при включенном PAE процесс не может получить доступ к более чем 4 ГБ памяти.

Конечно, с 64-разрядной ОС это ограничение в 4 ГБ больше не существует.

2.2. Память в Java

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

2.3. Куча Java

В куче виртуальная машина Java (JVM) хранит все объекты, созданные приложением Java, например с помощью оператора «новый». Сборщик мусора Java (gc) может логически разделить кучу на разные области, чтобы сборщик мусора мог быстрее идентифицировать объекты, которые можно удалить.

2.4. Стек Java

Стек — это место, где хранятся вызовы методов и локальные переменные. Если вызывается метод, то его кадр стека помещается на вершину стека вызовов. Фрейм стека содержит состояние метода, включая выполняемую строку кода и значения всех локальных переменных. Метод на вершине стека всегда является текущим выполняемым методом для этого стека. У потоков есть собственный стек вызовов.

2.5. Уклонение от анализа

Как было сказано ранее, объекты Java создаются и хранятся в куче. Язык программирования не дает возможности позволить программисту решить, следует ли генерировать объект в стеке. Но в некоторых случаях было бы желательно разместить объект в стеке, так как выделение памяти в стеке дешевле, чем выделение памяти в куче, освобождение памяти в стеке бесплатно, а среда выполнения эффективно управляет стеком.< /p>

Поэтому JVM использует внутренний escape-анализ, чтобы проверить, используется ли объект только с потоком или методом. Если JVM обнаружит это, она может решить создать объект в стеке, повысив производительность программы Java.

2.6. Утечки памяти

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

3. Сборщик мусора

JVM автоматически повторно собирает память, которая больше не используется. Память для объектов, на которые больше не ссылаются, будет автоматически освобождена сборщиком мусора. Чтобы убедиться, что сборщик мусора начинает работать, добавьте в виртуальную машину аргумент командной строки "-verbose:gc".

4. Параметры памяти для виртуальной машины Java

JVM работает с фиксированной доступной памятью. Как только эта память будет превышена, вы получите «java.lang.OutOfMemoryError».JVM пытается сделать разумный выбор доступной памяти при запуске (подробности см. в настройках Java), но вы можете заменить значение по умолчанию следующими параметрами.

Чтобы повысить производительность, вы можете использовать определенные параметры в JVM.

Установите минимальный доступный объем памяти для JVM на 1024 МБ

Установите максимально доступную память для JVM на 1800 мегабайт. Приложение Java не может использовать больше памяти кучи, чем указано в этом параметре.

Увеличьте значения этих параметров, чтобы избежать следующей ошибки: «Исключение в потоке java.lang.OutOfMemoryError: пространство кучи Java». Обратите внимание, что вы не можете выделить больше памяти, чем доступно физически.

Если вы запускаете программу на Java из командной строки, используйте, например, следующую настройку: java -Xmx1024m YourProgram. В Eclipse вы можете использовать аргументы виртуальной машины в конфигурации запуска.

5. Потребление памяти и время выполнения

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

5.1. Потребление памяти

5.2. Время выполнения Java-программы

Используйте System.currentTimeMillis(), чтобы получить время начала и время окончания и вычислить разницу.

6. Ленивая инициализация

Если создание переменной обходится очень дорого, иногда полезно отложить создание этой переменной до тех пор, пока она не понадобится. Это называется ленивой инициализацией. В общем случае ленивую инициализацию следует использовать только в том случае, если анализ показал, что это действительно очень затратная операция. Это основано на том факте, что ленивая инициализация затрудняет чтение кода. Я использую проект "de.vogella.performance.lazyinitialization" для примеров в этой главе. И иметь собственное поле.

6.1. Параллелизм — обзор

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

7. JIT-компилятор

JIT-компилятор Java компилирует байт-код Java в собственный исполняемый код во время выполнения вашей программы. Это значительно увеличивает время выполнения вашей программы. Компилятор JIT использует информацию о времени выполнения для определения частей вашего приложения, которые требуют интенсивного выполнения. Эти так называемые «горячие точки» затем переводятся в собственный код. По этой причине компилятор JIT также называют компилятором «горячих точек». JIT сохраняет исходный байт-код и собственный код в памяти, потому что JIT также может решить, что определенные шаги компиляции должны быть пересмотрены.

8. Использование VisualVM (jvisualvm)

8.1. Что такое VisualVM?

jvisualvm – это инструмент для анализа поведения вашего Java-приложения во время выполнения. Это позволяет вам отслеживать работающую программу Java и видеть ее потребление памяти и процессора. Его также можно использовать для создания дампа кучи памяти для анализа объектов в куче.

8.2. Создание дампа кучи с помощью

Вы можете использовать VisualVM для создания дампа кучи локально работающего приложения. Это создает временный файл, пока вы явно не сохраните его. Если вы не сохраните файл, он будет удален при завершении работы приложения, из которого вы взяли дамп кучи.

9. Нагрузочный тест

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

Читайте также: