Введение

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

Python не взаимодействует с памятью - только с её виртуальным представлением. В процессе выполнения программы операционная система создаёт процесс и выделяет под него ресурсы. В отличие от С/С++ мы не можем управлять памятью из кучи напрямую, а делаем это посредством memory manager, который и обращается к памяти через Python/C API.

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

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

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

Виртуальная память представляет собой иерархическую структуру, оптимизированную под блоки размером 256Кб.

  • Арена - 256Кб

  • Пул - 4Кб

  • Блок - от 16 до 512 байт

Блок

Содержит не более одного объекта и находится в одном из трёх состояний:

  • untouched - блок ещё не использовался

  • free - блок использовался механизмом памяти, но больше не содержит использованных программой данных

  • allocated - блок хранит данные

Пул

Пул также имеет три состояния:

  • used - занят

  • full - заполнен

  • empty - пуст (от used отличаются отсутствием allocated блоков) Пулы одного типа и одного размера блоков организованы в двусвязные списки.

Арена

Хранит в себе пулы любых видов. Арены хранятся в двусвязном списке и отсортированы по количеству доступных пустых пулов.

Освобождение памяти: счётчик ссылок и сборщик мусора

Так в Python всё является объектом, то каждое существо имеет прародителя - это PyObject. В нём определены счётчики ссылок и указатель на фактический тип объекта. Это хорошо работает пока Python не сталкивается с циклическим созданием ссылок. Например, когда два объекта ссылаются друг на друга. Для борьбы с такими проблемами поднимается сборщик мусора.

Советы

  • Обращайте внимание на работу с неизменяемыми объектами. К примеру, вместо присваивания строк, используйте .join() или .format().

  • Избегайте вложенных циклов. Это приводит к созданию чрезмерно большого количество объектов в виртуальной памяти процесса.

  • Используйте кэширование.

  • Профилируйте код.

Заключение

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

Комментарии (5)


  1. fenrir1121
    00.00.0000 00:00
    +3

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

    Так может расскажите как вы применили подобное знание на каком-то проекте пока не поздно?
    А не этот вольный хромой пересказ статьи "Memory Management" с RealPython?


  1. CrazyElf
    00.00.0000 00:00
    +2

    Не понял насчёт присваивания строк. Наверное имелось в виду сложение строк? Присваивание строк - это присваивание ссылки на строку в новую переменную, само по себе это не проблема.

    И что насчёт вложенных циклов? Сами по себе циклы не проблема. Имелось в виду создание каких-то локальных переменных внутри этих циклов или что?


  1. Eugeen1948
    00.00.0000 00:00
    -1

    Что особенно занимает, так это про "широкомасштабные коммерческие проекты". Какой язык программирования для соответствующего проекта будет наиболее эффективным? Вот, например, коды для расчета безопасности для АЭС (Атомных электростанций) ATHLET, Relap-5 стоят десятки тысяч долларов, да + еще и обучение. И все такие коды написаны на FORTRAN! А почему? Да потому, что многие умники пытались превзойти FORTRAN по компактности и быстродействию кода, переписывая на С++ или Pyton, и были сильно разочарованы результатами. У меня есть программка, написанная еще на FORTRAN - ЦЕРН для БЭСМ-6 в 1975 г. Мой старший сын попытался её ускорить на С++ (он, в свои 42 года весьма умелый и знающий специалист). После многих попыток он признал, что код на FORTRAN нельзя ничем улучшить, кроме Ассемблера (да и то не сильно). Интересно, что оптимизирующий компилятор с Фортрана для компьютеров IBM был написан на Фортране., что по мнению разработчиков позволило довести его до совершенства! А есть ли такие примеры в других языках?


    1. CrazyElf
      00.00.0000 00:00

      Кстати, для Фортрана есть и современный вполне компилятор. На нём часть математических библиотек для Питона написана. Судя по всему, этот код практически такой же быстрый как С++, раз никто эти библиотеки на С++ не переписывает.


      1. Ermak
        00.00.0000 00:00

        Так и Visual Fortran вполне себе существует.