Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.
Показано с 1 по 1 из 1
  1. #1
    Аватар для Daniel_Cortez
    "Это не хак, это фича"

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    2,192
    Репутация:
    2589 ±

    Мифы о Pawn-скриптинге - #9

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


    Миф 9: "Для экономии памяти лучше всегда использовать PVar'ы".

    Статус: Опровергнут.

    Описание:
    Ещё один миф о мнимой оптимизации. Как ни странно, распространён преимущественно у более-менее разбирающихся скриптеров, нежели у новичков.
    Заблудшие в подтверждение своим словам приводят доводы о том, что якобы PVar'ы занимают место только тогда, когда используются (до вызова DeletePVar), и поэтому можно сэкономить память, используя их вместо обычных переменных/массивов в Pawn.

    Доказательство:
      Открыть/закрыть
    Для начала изучим структуру PVar'ов, её можно найти в утекших исходниках SA-MP 0.3d (учитывая темпы развития стагнации мультиплеера, можно смело предположить, что в последней версии ничего не изменилось).
    Собственно, вот сама структура: https://github.com/Sasuke78200/open-..._var.h#L13-L22
      Открыть/закрыть
    1. typedef struct PVAR_DATA_t
    2. {
    3. #pragma pack( 1 )
    4. char pVarName[MAX_PVAR_NAME + 1];
    5. BOOL isReadOnly;
    6. uint32_t pVarType;
    7. int intValue;
    8. float floatValue;
    9. char* stringValue;
    10. } PVAR_DATA;

    Для тех, кому лень считать: структура занимает 58 байт, т.е. по 58 байт занимает каждый PVar. Для сравнения, обычная переменная в Pawn занимает всего 4 байта.
    Выглядит структура довольно "интересно". Свойство isReadOnly позволяет перевести PVar в состояние "только для чтения", но эта возможность нигде не используется (в SA-MP нет PVar'ов, доступных только для чтения).
    Кроме того, для хранения данных отведены целых 3 отдельных свойства: одно для целых чисел, другое для вещественных и третье для строк, что довольно странно, поскольку нельзя использовать PVar для одновременного хранения данных разных типов (т.е. нельзя, например, сохранить сразу число и строку).

    В том же исходном файле ниже можно найти структуру класса CPlayerVar: https://github.com/Sasuke78200/open-..._var.h#L24-L52
      Открыть/закрыть
    1. class CPlayerVar
    2. {
    3. #pragma pack( 1 )
    4. public:
    5.  
    6. PVAR_DATA pVars[MAX_PVARS];
    7. BOOL isPVarActive[MAX_PVARS];
    8. uint32_t upperIndex;
    9.  
    10. CPlayerVar();
    11. ~CPlayerVar();
    12.  
    13. int AddVar(char* varName);
    14. int DeleteVar(char* varName);
    15.  
    16. int SetIntVar(char* varName, int varValue, BOOL readOnly = 0);
    17. int SetStringVar(char* varName, char* varString, BOOL readOnly = 0);
    18. int SetFloatVar(char* varName, float varValue, BOOL readOnly = 0);
    19.  
    20. int GetIntVar(char* varName);
    21. char* GetStringVar(char* varName);
    22. float GetFloatVar(char* varName);
    23.  
    24. int GetVarType(char* varName);
    25. char* GetVarNameFromID(int pVarID);
    26.  
    27. int FindVarID(char* varName);
    28. void UpdateUpperID();
    29. };

    Это структура, место для которой выделяется отдельно для каждого игрока при подключении и высвобождается при выходе игрока с сервера.
    Объявление MAX_PVARS можно найти в том же файле, оно равно 800 (собственно, уже давно известно, что можно создать до 800 PVar'ов для каждого игрока).
    В структуре можно сразу же заметить самое первое свойство:
    1. PVAR_DATA pVars[MAX_PVARS];

    Это говорит о том, что под все 800 PVar'ов используется один общий блок памяти на каждого игрока, а значит все утверждения о том, что "PVar можно удалить и он больше не будет занимать место" ошибочны.

    Проверим наш вывод. Найдём в файле class_player_var.cpp все случаи использования функций malloc/calloc/free и операторов new/delete.
    Никакие функции для динамического выделения памяти там не используются, а new и delete используются только для резервирования/высвобождения места под строку, сохраняемую с помощью SetPVarString.
    Остальное содержимое хранится в одном общем для всех 800 PVar'ов блоке памяти, который остаётся зарезервированным на протяжении всего времени нахождения игрока на сервере. Что и требовалось доказать.

    Вывод: PVar'ы нисколько не экономят память, и вообще некорректно говорить о какой-либо экономии, поскольку под них постоянно используется один общий блок памяти.


    P.S.: Рассматривалось лишь утверждение про экомию памяти при "создании" и "удалении" PVar'ов (на самом деле память под них резервируется/высвобождается не в SetPVar(Int/Float/String)/DeletePVar, а при подключении/выходе игрока).
    P.P.S: Отдельный блок памяти может выделяться под строку при использовании SetPVarString, оно же и высвобождается при вызове DeletePVar, но остальных типов данных и самих PVar'ов это не касается. Как результат, в некоторых случаях может быть целесообразно использование PVar'ов для хранения строк.


    Специально для Pro-Pawn.ru
    Не разрешается копирование данной статьи на других ресурсах без разрешения автора.
    Индивидуально в ЛС по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).

  2. 16 пользователя(ей) сказали cпасибо:
    #Vito (14.07.2016) Alanchick (13.07.2016) ArtZet (15.08.2016) BadPawn (14.07.2016) Desulaid (13.07.2016) De_Lay (15.07.2016) gangzone.ini (13.07.2016) Geebrox (13.07.2016) kushichka (14.07.2016) MrJu[N]ior (14.07.2016) Nurick (13.07.2016) Processing (13.07.2016) Profyan (18.07.2016) StevenH (13.07.2016) Unreal (13.07.2016) _lizard (13.07.2016)
 

 

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •