На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются.
4. Используйте теги [ code=cpp ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Старайтесь формулировать свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной и более давности без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта (C++) user posted image FAQ Форума user posted image Наши Исходники user posted image Поиск по Разделу user posted image MSDN Library Online (Windows Driver Kit) user posted image Google

Ваше мнение о модераторах: user posted image B.V.
Модераторы: B.V.
  
> gcc как определить и выделить максимальный непрерывный блок динамической памяти? , OS Linux, OS Windows
    Разрабатываю программы решения Задачи Коммивояжера (ЗК) на языке Си в среде Qt. Операционные системы: Linux, Windows.
    Особенность ЗК - для решения этой задачи большой размерности (например, 300 городов) часто бывает мало 8-16-32-64Гб RAM.
    Особенно нетерпимо - сброс огромных массивов данных, по которым идет расчет, из RAM в SWAP.

    Вот и возникает задача: как определить максимально доступный объем непрерывной динамической памяти?
    Поиск в Интернете привел к созданию такого фрагмента кода для достижения указанной цели:
    ExpandedWrap disabled
      // Операционная система определяется макросом WINVER (есть в Windows и нет в Linux)
      #ifndef WINVER
      #include <sys/sysinfo.h>
      #else
      #include <sysinfoapi.h>
      #endif
       
      // Переменные для информации об основных параметрах ОС (главным образом - RAM). Заодно определяется "слэш" в файловой системе
      #ifndef WINVER
          struct sysinfo osInfo;
          char cSl = '/';
      #else
          MEMORYSTATUSEX osInfo;
          char cSl = '\\';
      #endif
       
      unsigned long long int
          // Общий объем доступной непрерывной динамической RAM, шаг при поиске iMemMax
          iMemMax, iDMem;
      char
          // Указатель, "нарезающий" выделяемую память для массивов данных, используемых при решении ЗК
          *pByte;
       
       
      // Чтение информации о состоянии операционной системы
      #ifndef WINVER
           sysinfo(&osInfo);
           iMemMax = osInfo.freeram;
           // "Ефрейторский" зазор - настолько пошагово уменьшается память, если ее нельзя выделить
           iDMem   = osInfo.totalram / 1000 + 1;
      #else
           osInfo.dwLength = sizeof(osInfo);
           if (!GlobalMemoryStatusEx(&osInfo)) { // osInfo.freeram;
               printf("Не могу определить размер динамической памяти!");
               return -1;
           }
           iMemMax = osInfo.ullAvailPhys;
           iDMem   = osInfo.ullTotalPhys / 1000 + 1;
      #endif
           pByte = (char *)calloc(iMemMax, sizeof(char));
           while (!pByte && (iMemMax > iDMem)) {
               iMemMax -= iDMem;
               pByte = (char *)calloc(iMemMax, sizeof(char));
           }
           if (!pByte) {
               printf("Не могу выделить динамическую память!\n");
               return -1;
           }
      #ifndef WINVER
           printf("Динамической памяти "); printf("RAM = %lld Mbyte\n",  iMemMax / 1048576);  // 1048576   = 1024 *1024
      #else
           printf("Динамической памяти "); printf("RAM = %I64d Mbyte\n", iMemMax / 1048576); // 1048576   = 1024 *1024
      #endif


    В чем состоит проблема?
    Как это ни странно, в Windows-7 32bit проблем нет: программа в Qt (компиляция realese) выделяет 1600Мб RAM, а в mingw32 (ключ -O3) выделяет 1860Мб RAM.

    Все проблемы с Linux.
    Когда многократно запускаешь скомпилированную программу, сначала идет все хорошо (пусть будет 8Гб физической RAM):
    например, при первом запуске выделяется блок в 7000Мб RAM;
    при втором запуске (пример) выделяется уже 7200Мб RAM;
    и так далее - при каждом следующем запуске ОС освобождает все больше RAM для решения Задачи Коммивояжера.

    Заканчивается все тем, что из 8192Мб физической RAM выделяется, скажем, 7860Мб RAM и при этом часть памяти начинает сидеть в SWAP!
    То есть начинает использоваться SWAP на HDD!
    Визуально это наблюдается так: HDD начинает перманентно "трещать". Трещит и 5 минут, и 10 минут, и 20 минут...
    Мне приходится делать вот что: начиная с некоторого момента перед запуском программы решения ЗК приходится запускать LibreOffice только с одной целью - чтобы офис частично занял RAM (после запуска ЗК я Офис закрываю).

    Вопрос, собственно, такой: как в Linux сделать так, чтобы выделяемый блок памяти (близкий к максимальному) сидел четко в RAM?
    Может мой код надо как-то подрегулировать? (Замечания и предложения, разумеется, принимаются).
    Сообщение отредактировано: Qraizer -
      Строго говоря, дело тут не в Windows или Linux, дело в разрядности приложения. В 64-биной винде будет то же самое.
      Задача, в общем-то неоднозначная. Предположим, ты определил эффективный для тебя размер региона памяти. Ок, тебя ОСь свопить не будет... но ведь в системе есть и другие процессы, и оставив им очень мало памяти, ты заставишь ОСь свопать их, и они, получая управление даже изредка, всё равно будут деградировать производительность системы в целом, а значит и твою тоже. Готовых рецептов тут просто не может быть, т.к. золотая середина завист от факторов, которые достоверно просчитать в общем случае просто невозможно.

      Добавлено
      Я бы предложил сначала просто получить регион максимального размера, в WinAPI это VirtualAlloc(). Так ты получишь потенциально самый большой размер региона, который только возможно, но в 64-х битах наверняка сповиться он будет безбожно. Затем попробовать поколдовать над размерами рабочего пространства посредством SetProcessWorkingSetSize(). Так ты сможешь получить эффективный размер региона, который система может позволить тебе оставлять резидентным в памяти, хотя и без гарантии этой резидентности и ценой деградации производительности системы в целом. И наконец залочить регион в памяти с помощью VirtualLock(). Так ты получишь максимально большой, но всё ещё разумный по размеру регион памяти, который не будет свопаться. После этого можно VirtualFree() декоммитить "лишние" страницы, отдав т.о. избыточно отхапанную память на другие нужды и ... посмотреть, что из этого алгоритма получилось. Что и как из этого будет применимо в Linux, без понятия.

      Добавлено
      Естественно, подбор этих максимумов надо делать разумно, например, дихотомией.

      Добавлено
      P.S. Я тут по быстрому накидал нечто вот такое (внимание! синтетика! в продакшне как есть не использовать!):
      ExpandedWrap disabled
        #define NOMINMAX
        #include <windows.h>
        #include <iostream>
        #include <limits>
         
        int main()
        {
          size_t size    = std::numeric_limits<decltype(size)>::max(),
                 oldSize = size;
          void  *mem;
         
          do
          {
            mem = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
            if (mem == NULL)
            {
              oldSize = size;
              size  >>= 1;
              continue;
            }
         
            size_t newSize = (oldSize >> 1) + (size >> 1);
         
            oldSize = size;
            size    = newSize;
            VirtualFree(mem, 0, MEM_RELEASE);
          } while (size != oldSize);
         
          size_t allocated = size;
         
          mem = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
          if (mem == NULL)
            return std::cout << "Ops!\n",
                   1;
          std::cout << "Allocated " << size << " bytes" << std::endl;
         
          do
          {
            if (SetProcessWorkingSetSize(GetCurrentProcess(), size, size) == FALSE)
            {
              oldSize = size;
              size  >>= 1;
              continue;
            }
         
            size_t newSize = (oldSize >> 1) + (size >> 1);
         
            oldSize = size;
            size    = newSize;
          } while (size != oldSize);
         
          if (SetProcessWorkingSetSize(GetCurrentProcess(), size, size) == FALSE)
            return std::cout << "Ops 2!\n",
                   2;
          std::cout << "Residented " << size << " bytes" << std::endl;
         
          do
          {
            if (VirtualLock(mem, size) == FALSE)
            {
              oldSize = size;
              size  >>= 1;
              continue;
            }
         
            size_t newSize = (oldSize >> 1) + (size >> 1);
         
            oldSize = size;
            size    = newSize;
            VirtualUnlock(mem, oldSize);
          } while (size != oldSize);
         
          if (VirtualLock(mem, size) == FALSE)
            return std::cout << "Ops 3!\n",
                   3;
          std::cout << "Locked " << size << " bytes" << std::endl;
         
          SetProcessWorkingSetSize(GetCurrentProcess(), size, size);
          VirtualFree((char*)mem + size, allocated - size, MEM_DECOMMIT);
         
          std::cout << "Ok" << std::endl;       // <- тут бряк
         
          VirtualUnlock(mem, oldSize);
          SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
          VirtualFree(mem, 0, MEM_RELEASE);
        }
      и получил под 32-битной 7кой с 4Гб на борту
      ExpandedWrap disabled
        Allocated 1431655763 bytes
        Residented 1431655762 bytes
        Locked 954437164 bytes
      остановившись под отладчиком в указанном месте и запустил второй процесс вот с такими результатами:
      ExpandedWrap disabled
        Allocated 1431655763 bytes
        Residented 477218569 bytes
        Locked 318145701 bytes
        Ok
      При этом на фоне работал тяжёлый JavaScript-овый алгоритм в браузере, целиком отжирая одно ядро у Core i3. Ну т.е. цифры выглядят разумными, и система вполне жива и не деградирует. Есть вероятность, что эта синтетика вполне может служить примером золотой середины.

      Добавлено
      Естественно, эксперимент не чистый, процесс под анализом стоит и ничего не делает. Ну и буду дома, проверю ещё на 64-х битах с 16Гб.
      Сообщение отредактировано: Qraizer -
        Результаты на 64-х битах в сходных условиях: 16Гб на i5 с одним нагруженным тем же тяжёлым скриптом ядром:
        ExpandedWrap disabled
          Allocated 22906492243 bytes
          Residented 11453246118 bytes
          Locked 7635497391 bytes
        ExpandedWrap disabled
          Allocated 17179869181 bytes
          Residented 1610612733 bytes
          Locked 1073741819 bytes
        Первый экземпляр запускался, как и следовало ожидать, очень тяжело, на цикле VirtualLock() до бряка я успел сходить покурить. Второй экземпляр запустился и дошёл до бряка быстро, за пару секунд. После полуминуты в таком состоянии свопы прекратились, фоновый скрипт нормально работал, система потихонечку отходила от перенапряга, физическая память в итоге оказалась утилизирована на 88%.

        P.S. На момент запуска первого экземпляра память была утилизирована на 42%, так что можно было ожидать ~9Гб залоченной памяти, но система оказалась умней.
        Сообщение отредактировано: Qraizer -
        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
        0 пользователей:


        Рейтинг@Mail.ru
        [ Script execution time: 0,0290 ]   [ 18 queries used ]   [ Generated: 25.04.24, 17:20 GMT ]