Да не паникуй ты так. Это количество страниц, к котрым онадобился доступ когда их не было в оперативной памяти. А если еще точнее, то количество страниц, к котрым онадобился доступ когда их не было в рабочем наборе приложения, что не значит что их не было в оперативе.
> Это нормально, когда у программы он растет со скоростью > 2-3 тыс единиц в секунду?
это ошибка доступа к странице памяти, при её возникновении системы выгружает нужную страницу из файла подкачки в ОЗУ. > Это нормально, когда у программы он растет со скоростью > 2-3 тыс единиц в секунду?
не очень (хотя тут нужно смотреть конкретную ситуацию), нужно побольше ОЗУ.
> Это нормально, когда у программы он растет со скоростью > 2-3 тыс единиц в секунду?
Я счас подергал окошко оперы за края, погонял апатчь, до 5 тышь в секунду доходило. Вот же уродский оптимайзер памяти у винды 🙁 Так что пара тысячь в секунду — вполне нормально.
procedure FastDIB2Bitmap(Src:TFastDIB;Dst:TBitmap); begin if Src.Handle<>0 then begin Dst.Handle:=Src.Handle; // bitmaps can be selected for only one device context at a time if(Src.hDC<>0)and Src.FreeDC then DeleteDC(Src.hDC); if(Src.hPen<>0)then DeleteObject(Src.hPen); if(Src.hFont<>0)then DeleteObject(Src.hFont); if(Src.hBrush<>0)then DeleteObject(Src.hBrush); Src.hDC:=0; Src.FreeDC:=False; Src.FreeBits:=False; Src.FreeHandle:=False; end; end;
Вот такие преобразования моя программа делает до 200 в секунду. Если я комментирую преобразование, то счетчик не растет практически.
Памяти 100% достаточно. Ее количество не влияет на этот счетчик. 2Гб ее.
> в Делфи идентификатор объекта является указателем на объект > )
:Р
По логике, нужно сначала всё освободить, потом присваивать Handle. Возможно, и освобождать необязательно, во всяком случае в примере Bumpmap сделано так:
procedure TBumpForm.SetThumbnail(Image:TImage; Bmp:TFastDIB); var Tmp: TFastDIB; begin Tmp:=TFastDIB.Create; Tmp.SetSize(105,105,Bmp.Bpp); if Tmp.Bpp=8 then begin Tmp.Colors^:=Bmp.Colors^; Tmp.UpdateColors; end;
А вообще, откуда надобность выполнять подобное преобразование 200 раз/c? Может лучше выкинуть TBitmap и выполнять все операции с TFastDIB? А то мне сейчас лень смотреть, но подозреваю, что в TBitmap.SetHandle куда больше действий, чем просто присвоение переменной.
> А вообще, откуда надобность выполнять подобное преобразование > 200 раз/c?
Да есть вот задачи. Видеонаблюдение.
> Может лучше выкинуть TBitmap и выполнять все операции с > TFastDIB?
Так и планирую сделать, но есть свои грабли и очень много вносить изменений. В принципе FastDIB тут прикручен из-за фантастически быстрой SetSize.
> TBitmap.SetHandle куда больше действий, чем просто присвоение > переменной.
Да, там намного больше действий.
> Sapersky
Не подскажите, как правильно скопировать один TFastDIB в другой. Не Assign(), а именно копирование? У меня вот какая штука:
Во вторичном потоке происходит декодирование JPEG в TFastDIB. Далее этот FastDIB с сообщением высылается в основной поток и там преобразуется в TBitmap, который и отрисовывается при необходимости в основном потоке по WM_PAINT. Так сделано сейчас. Так вот получается, что и основной поток и вторичный на деле же работают с одним и тем же хэндлом одного и того же битмапа по сути. Ведь FastDIB2Bitmap просто присваивает хэндл. И пока первичный поток отрисовывает его на окне вторичный ведь может и поменять его содержимое. Или я неправ? Так можно делать или надо полностью копироваить битмап в основной поток и там работать с ним?
Хм, а я кажеться понял почему так много ошибок доступа в этом месте. Потому что по Dst.Handle:=Src.Handle; Dst фактически заново создаеться, под новый битмап выделяеться память. А менеджер памяти в виндовсе имеет такое замечательное свойство, не выделять память физически, а лишь помечать страницы как зарезервированые. А вот когда уже на новый хэндл уже копируеться изображение со старого, идет непосредственное обращение к страницам, и они выделяются физически (в ОП), а счетчик ошибок доступа мотает. Так что эта строчка имхо — большая дыра в производительности. Попробуй как минимум создавать TBitmap как DIB, как максимум, здесь вобще нужно логику программы переделывать.
> Так вот получается, что и основной поток и вторичный на > деле же работают с одним и тем же хэндлом одного и того > же битмапа по сути.
Скорее всего нет. Как я понимаю невозможно преобразовать DDB в DIB не выделив под него второй хэндл.
> Потому что по Dst.Handle:=Src.Handle; Dst фактически заново > создаеться, под новый битмап выделяеться память
Да, получается, что так.
> Так что эта строчка имхо — большая дыра в производительности.
Может быть, но это далеко не самая тяжелая операция. Декодирование из JPEG во вторичных потоках занимает в тысячи раз больше времени.
←→ Sapersky ( 2007-05-02 00:38 ) [16]
Не подскажите, как правильно скопировать один TFastDIB в другой. Не Assign(), а именно копирование?
Dst.MakeCopy(Src, True); // делается SetSize и Move Или можно (при UseGDI = True) установить размер Dst = Src, потом Src.Draw(Dst.hDC, 0, 0); // фактически BitBlt удобно тем, что конвертирует битмапы разных форматов, хотя, как правило, не очень качественно. Впрочем, для этого есть FConvert.pas.
И пока первичный поток отрисовывает его на окне вторичный ведь может и поменять его содержимое. Так можно делать или надо полностью копироваить битмап в основной поток и там работать с ним?
•Ошибок отсутствия страницы в памяти/сек – ошибка отсутствия в памяти. Как правило, она может быть критической (но не всегда). Также может указывать на нехватку оперативной памяти. Такая ошибка возникает в тех случаях, когда система использует файл подкачки, который находится на жестком диске. Жесткий диск работает медленнее оперативной памяти, и использование файла подкачки снижает быстродействие системы. Если подобные ошибки слишком часто возникают, лучше расширить оперативную память.
1. Откройте командную строку с Административными правами. 2. В командной строке введите следующую команду и нажмите клавишу ВВОД:
По окончании выложите C:\windows\Logs\CBS\ CBS.log в архиве.
Запустите AIDA64 Portable от имени Администратора > Сверху, в окне программы AIDA нажмите «Отчет» > Далее > выберите «Аппаратные разделы» > Далее > Простой текст > Готово > Сохранить в файл.
Да не паникуй ты так. Это количество страниц, к котрым онадобился доступ когда их не было в оперативной памяти. А если еще точнее, то количество страниц, к котрым онадобился доступ когда их не было в рабочем наборе приложения, что не значит что их не было в оперативе.
> Это нормально, когда у программы он растет со скоростью > 2-3 тыс единиц в секунду?
это ошибка доступа к странице памяти, при её возникновении системы выгружает нужную страницу из файла подкачки в ОЗУ. > Это нормально, когда у программы он растет со скоростью > 2-3 тыс единиц в секунду?
не очень (хотя тут нужно смотреть конкретную ситуацию), нужно побольше ОЗУ.
> Это нормально, когда у программы он растет со скоростью > 2-3 тыс единиц в секунду?
Я счас подергал окошко оперы за края, погонял апатчь, до 5 тышь в секунду доходило. Вот же уродский оптимайзер памяти у винды 🙁 Так что пара тысячь в секунду — вполне нормально.
Я вот попытался локализовать в своей программе место, которое более всего увеличивает счетчик — оказалось это место в FastDIB. А именно:
procedure FastDIB2Bitmap(Src:TFastDIB;Dst:TBitmap); begin if Src.Handle<>0 then begin Dst.Handle:=Src.Handle; // bitmaps can be selected for only one device context at a time if(Src.hDC<>0)and Src.FreeDC then DeleteDC(Src.hDC); if(Src.hPen<>0)then DeleteObject(Src.hPen); if(Src.hFont<>0)then DeleteObject(Src.hFont); if(Src.hBrush<>0)then DeleteObject(Src.hBrush); Src.hDC:=0; Src.FreeDC:=False; Src.FreeBits:=False; Src.FreeHandle:=False; end; end;
Вот такие преобразования моя программа делает до 200 в секунду. Если я комментирую преобразование, то счетчик не растет практически.
Памяти 100% достаточно. Ее количество не влияет на этот счетчик. 2Гб ее.
> в Делфи идентификатор объекта является указателем на объект > )
:Р
←→ Sapersky ( 2007-05-01 20:51 ) [10]
Я вот попытался локализовать в своей программе место, которое более всего увеличивает счетчик — оказалось это место в FastDIB.
По логике, нужно сначала всё освободить, потом присваивать Handle. Возможно, и освобождать необязательно, во всяком случае в примере Bumpmap сделано так:
procedure TBumpForm.SetThumbnail(Image:TImage; Bmp:TFastDIB); var Tmp: TFastDIB; begin Tmp:=TFastDIB.Create; Tmp.SetSize(105,105,Bmp.Bpp); if Tmp.Bpp=8 then begin Tmp.Colors^:=Bmp.Colors^; Tmp.UpdateColors; end;
А вообще, откуда надобность выполнять подобное преобразование 200 раз/c? Может лучше выкинуть TBitmap и выполнять все операции с TFastDIB? А то мне сейчас лень смотреть, но подозреваю, что в TBitmap.SetHandle куда больше действий, чем просто присвоение переменной.
Ещё, имейте в виду, что FastGate — это не оригинальный FastLIB. Автор этого модуля уже допускал ляпы при «улучшении» библиотеки, так что аккуратнее с ним (хотя, строго говоря, и «оригинал» не безгрешен).
> А вообще, откуда надобность выполнять подобное преобразование > 200 раз/c?
Да есть вот задачи. Видеонаблюдение.
> Может лучше выкинуть TBitmap и выполнять все операции с > TFastDIB?
Так и планирую сделать, но есть свои грабли и очень много вносить изменений. В принципе FastDIB тут прикручен из-за фантастически быстрой SetSize.
> TBitmap.SetHandle куда больше действий, чем просто присвоение > переменной.
Да, там намного больше действий.
> Sapersky
Не подскажите, как правильно скопировать один TFastDIB в другой. Не Assign(), а именно копирование? У меня вот какая штука:
Во вторичном потоке происходит декодирование JPEG в TFastDIB. Далее этот FastDIB с сообщением высылается в основной поток и там преобразуется в TBitmap, который и отрисовывается при необходимости в основном потоке по WM_PAINT. Так сделано сейчас. Так вот получается, что и основной поток и вторичный на деле же работают с одним и тем же хэндлом одного и того же битмапа по сути. Ведь FastDIB2Bitmap просто присваивает хэндл. И пока первичный поток отрисовывает его на окне вторичный ведь может и поменять его содержимое. Или я неправ? Так можно делать или надо полностью копироваить битмап в основной поток и там работать с ним?
Хм, а я кажеться понял почему так много ошибок доступа в этом месте. Потому что по Dst.Handle:=Src.Handle; Dst фактически заново создаеться, под новый битмап выделяеться память. А менеджер памяти в виндовсе имеет такое замечательное свойство, не выделять память физически, а лишь помечать страницы как зарезервированые. А вот когда уже на новый хэндл уже копируеться изображение со старого, идет непосредственное обращение к страницам, и они выделяются физически (в ОП), а счетчик ошибок доступа мотает. Так что эта строчка имхо — большая дыра в производительности. Попробуй как минимум создавать TBitmap как DIB, как максимум, здесь вобще нужно логику программы переделывать.
Возникла другая проблема — как мне правильно передать с сообщением переменную типа TFastDIB из вторичного потока в первичный с сообщением и присвоить полченное в основном потоке значение переменной в первичном потоке. Просто присваиванием очевидно нельзя — возникают сразу утечки GDI ресурсов (вот здесь отличие от TBITMAP).
←→ Sapersky ( 2007-05-02 00:38 ) [16]
Не подскажите, как правильно скопировать один TFastDIB в другой. Не Assign(), а именно копирование?
Dst.MakeCopy(Src, True); // делается SetSize и Move Или можно (при UseGDI = True) установить размер Dst = Src, потом Src.Draw(Dst.hDC, 0, 0); // фактически BitBlt удобно тем, что конвертирует битмапы разных форматов, хотя, как правило, не очень качественно. Впрочем, для этого есть FConvert.pas.
И пока первичный поток отрисовывает его на окне вторичный ведь может и поменять его содержимое. Так можно делать или надо полностью копироваить битмап в основной поток и там работать с ним?
Если вторичный поток не изменяет размер битмапа, т.е. не портит указатель/Handle, то, наверное, можно его спокойно рисовать, в крайнем случае нарисуется половина старого, половина нового. Хотя сам не пробовал, не знаю, как функции GDI отнесутся к тому, что кто-то будет писать в используемую ими область памяти. Можно на всякий случай прицепить к битмапу крит. секцию. Если изменяет — тогда однозначно нужна или синхронизация, или копирование, или и то, и другое.
Просто присваиванием очевидно нельзя — возникают сразу утечки GDI ресурсов (вот здесь отличие от TBITMAP). Что такое «присваивание»? Если Assign — возможно, «аффтар» FastGate с ним напортачил в новой версии, пытаясь добиться того же поведения, что и у TBitmap. В оригинале это поведение довольно специфическое — битмап-источник уничтожается. В общем, лучше «присваивание» делать как Dst := Src с соответствующей синхронизацией или MakeCopy.
Большое спасибо. Метод TFastDib.MakeCopy() действительно то что нужно.
Счетчики ошибок страницы не растут. Утечек тоже нет. Как обстоят дела с производительностью такого решения выясняю.
Вот тут ответ на твой вопрос: https://social.technet.microsoft.com/Forums/ru-RU/0e7cb14d-99b8-48bd-aa2c-00594afa2cad/1084108610851080109010861088?forum=vistaru Если имеется в виду Page Fault то это не ошибки. Это просто значит что запрошеная страница (участок памяти размером 4К) была выгружена на диск и ее потребовалось загрузить в физическую память. Это совершенно нормальное явление в любых ОС с виртуальной памятью.
Черезмерное количество таких явлений однако может привести к снижению производительности и свидетельствует о недостатке физической памяти.
В случае вытесняющего алгоритма операционная система в любой момент времени может прервать выполнение текущего потока и переключить процессор на другой поток. В невытесняющих алгоритмах поток, которому предоставлен процессор, только сам решает, когда передать управление операционной системе.
Алгоритмы с квантованием.
Каждому потоку предоставляется квант времени, в течение которого поток может выполняться на процессоре. По истечении кванта операционная система переключает процессор на следующий поток в очереди. Квант обычно равен целому числу интервалов системного таймера1.
Алгоритмы с приоритетами.
Каждому потоку назначается приоритет (priority) – целое число, обозначающее степень привилегированности потока. Операционная система при наличии нескольких готовых к выполнению потоков выбирает из них поток с наибольшим приоритетом.
В Windows реализован смешанный алгоритм планирования – вытесняющий, на основе квантования и приоритетов.
Прерывание 14 —Страничная ошибка(#PF): Intel386 …
Генерируется, если страничный механизм активизирован (CR0.PG = 1) и при трансляции линейного адреса в физический возникает одна из следующих ситуаций:
Обработчик страничной ошибки получает информацию о ее причине из двух источников: кода ошибки, помещаемого в стек, и содержимого регистра CR2, который содержит линейный адрес, вызвавший ошибку. Код страничной ошибки имеет специальный формат (рис. 3.7.).
Прерванная программа после устранения причин, вызвавших страничную ошибку (например, загризки страницы в физическую память), может быть продолжена без каких-либо дополнительных корректировок.
Если страничная ошибка была вызвана в связи с нарушением привилегий страничной защиты, то бит доступа (A) в соответствующем элементе каталога страниц устанавливается. Поведение бита доступа в соответствующем элементе таблиц страниц для этого случая не регламентируется в процессорах Intel и может быть разным в различных моделях.
— ненадежности оперативной памяти
Графа «Ошибок отсутствия страницы в памяти/сек.»
В графе «Ошибок отсутствия страницы в памяти/сек.» (Hard Faults/sec) указано среднее за последнюю минуту количество ошибок отсутствия страницы в памяти в секунду. Если процесс пытается использовать больше физической памяти, чем доступно в данный момент времени, система записывает часть данных из памяти на диск — в файл подкачки. Последующее обращение к данным, сохраненным на диск, и называется ошибкой отсутствия страницы в памяти.
О чем говорят ошибки отсутствия страницы в памяти
Теперь, когда вы представляете, какие сведения собраны в таблице «Процессы», давайте посмотрим, как с их помощью следить за распределением памяти. При запуске приложений и работе с файлами диспетчер памяти отслеживает объем рабочего набора для каждого процесса и фиксирует запросы на дополнительные ресурсы памяти. По мере увеличения рабочего набора процесса, диспетчер соотносит эти запросы с потребностями ядра и других процессов. Если доступного адресного пространства недостаточно, диспетчер уменьшает объем рабочего набора, сохраняя данные из памяти на диск.
В дальнейшем при чтении этих данных с диска возникает ошибка отсутствия страницы в памяти. Это вполне нормально, но если ошибки происходят одновременно для разных процессов, системе требуется дополнительное время для чтения данных с диска. Слишком частые ошибки отсутствия страницы в памяти, соответственно, снижают быстродействие системы. Вам наверняка доводилось наблюдать неожиданное замедление работы всех приложений, которое затем также неожиданно прекращалось. Почти наверняка это замедление было связано с активным перераспределением данных между физической памятью и подкачкой.
Отсюда следует вывод: если ошибки отсутствия страницы в памяти для того или иного процесса происходят слишком часто и притом регулярно, компьютеру не хватает физической памяти.
Чтобы было удобнее наблюдать за процессами, вызывающими частые ошибки отсутствия страницы в памяти, можно отметить их флажками. При этом выбранные процессы переместятся наверх списка, а в графике ошибок отсутствия страницы в памяти будут представлены оранжевой кривой.
Стоит учитывать, что распределение памяти зависит от целого ряда других факторов, и мониторинг ошибок отсутствия страницы в памяти — не лучший и не единственный способ выявления проблем. Тем не менее, он может послужить неплохой отправной точкой для наблюдения.
В ОС Windows реализовано вытесняющее приоритетное планирование, когда каждому потоку присваивается определенное числовое значение — приоритет, в соответствии с которым ему выделяется процессор. Потоки с одинаковыми приоритетами планируются согласно алгоритму Round Robin (карусель). Важным достоинством системы является возможность вытеснения потоков, работающих в режиме ядра — код исполнительной системы полностью реентерабелен. Не вытесняются лишь потоки, удерживающие спин-блокировку (см. Синхронизация потоков ). Поэтому спин-блокировки используются с большой осторожностью и устанавливаются на минимальное время.
В системе предусмотрено 32 уровня приоритетов. Шестнадцать значений приоритетов (16-31) соответствуют группе приоритетов реального времени, пятнадцать значений (1-15) предназначены для обычных потоков, и значение 0 зарезервировано для системного потока обнуления страниц (см. рис. 6.2).
Рис. 6.2.Приоритеты потоков
Чтобы избавить пользователя от необходимости запоминать числовые значения приоритетов и иметь возможность модифицировать планировщик, разработчики ввели в систему слой абстрагирования приоритетов. Например, класс приоритета для всех потоков конкретного процесса можно задать с помощью набора констант-параметров функции SetPriorityClass, которые могут иметь следующие значения:
Относительный приоритет потока устанавливается аналогичными параметрами функции SetThreadPriority:
Совокупность из шести классов приоритетов процессов и семи классов приоритетов потоков образует 42 возможные комбинации и позволяет сформировать так называемый базовый приоритет потока
Базовый приоритет процесса и первичного потока по умолчанию равен значению из середины диапазонов приоритетов процессов (24, 13, 10, 8, 6 или 4). Смена приоритета процесса влечет за собой смену приоритетов всех его потоков, при этом их относительные приоритеты остаются без изменений.
Приоритеты с 16 по 31 в действительности приоритетами реального времени не являются, поскольку в рамках поддержки мягкого реального времени, которая реализована в ОС Windows, никаких гарантий относительно сроков выполнения потоков не дается. Это просто более высокие приоритеты, которые зарезервированы для системных потоков и тех потоков, которым такой приоритет дает пользователь с административными правами. Тем не менее, наличие приоритетов реального времени, а также вытесняемость кода ядра, локализация страниц памяти (см. Функционирование менеджера памяти ) и ряд дополнительных возможностей — все это позволяет выполнять в среде ОС Windows приложения мягкого реального времени, например, мультимедийные. Системный поток с нулевым приоритетом занимается обнулением страниц памяти. Обычные пользовательские потоки могут иметь приоритеты от 1 до 15.
Статьи к прочтению:
Пусть говорят — «Вы мне не верили, а я умерла»Выпуск от 11.09.217
Похожие статьи:
Одним из методов борьбы с фрагментацией является перемещение всех занятых участков в сторону старших либо в сторону младших адресов так, чтобы все…
На рис. 10 показана схема страничного распределения памяти. Виртуальное адресное пространство каждого процесса делится на части одинакового,…