Непрерывное поведение VirtualAlloc в Windows Mobile - PullRequest
2 голосов
/ 17 мая 2009

Я оптимизировал производительность памяти в приложении Windows Mobile и столкнулся с некоторыми различиями в поведении между VirtualAlloc на Win32 и Windows CE .

Рассмотрим следующий тест:

// Allocate 64k of memory
BYTE *a = (BYTE*)VirtualAlloc(0,       65536,
                              MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
// Allocate a second contiguous 64k of memory
BYTE *b = (BYTE*)VirtualAlloc(a+65536, 65536,
                              MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);

BYTE *c = a + 65528; // Set a pointer near the end of the first allocation
BOOL valid1 = !IsBadWritePtr(c, 8); // Expect TRUE
BOOL valid2 = !IsBadWritePtr(c+8, 4088); // Expect TRUE
BOOL valid3 = !IsBadWritePtr(c, 4096); // TRUE on Win32, FALSE on WinCE

Код «выделяет» 4096 данных, начиная с «c». На Win32 это работает. Я не могу найти в документации VirtualAlloc никаких упоминаний о том, является ли это законным или совпадением, но я нашел много примеров кода, который я нашел в Google и который ожидает такого поведения.

В Windows CE 5.0 / 5.2, если я использую блок памяти в «c», в 99% случаев проблем не возникает, однако на некоторых (не на всех) устройствах Windows Mobile 6 ReadFile & WriteFile завершится с ошибкой 87 (параметр неверен.). Я предполагаю, что ReadFile вызывает IsBadWritePtr или подобное и возвращает ложь из-за этого. Если я выполняю два ReadFile вызова, то все работает нормально. (Конечно, могут быть и другие вызовы API, которые также не будут работать.)

Я ищу способ расширить память, возвращаемую VirtualAlloc , чтобы я мог заставить работать выше. Резервирование большого объема памяти в Windows CE проблематично, поскольку каждый процесс получает только 32 МБ, а из-за загрузки других элементов невозможно зарезервировать большой объем памяти, не вызывая других проблем. (Можно зарезервировать больший объем памяти в общей области, но это также имеет другие проблемы.)

Есть ли способ получить VirtualAlloc для увеличения или объединения регионов без предварительного резервирования?

Я подозреваю, что это может быть проблематично, учитывая следующие примеры:

HANDLE hHeap1 = HeapCreate(0, 0, 0); // Heap defaults to 192k
BYTE * a1 = (BYTE*)HeapAlloc(hHeap1, 0, 64000); // +96 bytes from start of heap
BYTE * b1 = (BYTE*)HeapAlloc(hHeap1, 0, 64000); // +16 bytes from end of a1
BYTE * c1 = (BYTE*)HeapAlloc(hHeap1, 0, 64000); // +16 bytes from end of b1
BYTE * d1 = (BYTE*)HeapAlloc(hHeap1, 0, 64000); // +4528 bytes from end of c1

HANDLE hHeap2 = HeapCreate(0, 4*1024*1024, 4*1024*1024); // 4MB Heap
BYTE * a2 = (BYTE*)HeapAlloc(hHeap2, 0, 64000); // +96 bytes from start of heap
BYTE * b2 = (BYTE*)HeapAlloc(hHeap2, 0, 64000); // +16 bytes from end of a2
BYTE * c2 = (BYTE*)HeapAlloc(hHeap2, 0, 64000); // +16 bytes from end of b2
BYTE * d2 = (BYTE*)HeapAlloc(hHeap2, 0, 64000); // +16 bytes from end of c2

Ответы [ 3 ]

2 голосов
/ 25 мая 2009

Нет, это невозможно.

2 голосов
/ 23 мая 2009

Я бы не стал доверять IsBadWritePtr, посмотрите это: http://support.microsoft.com/kb/960154 Я думаю, что он что-то вроде пытается записать в память, и видит, получает ли он аппаратное исключение. Он обрабатывает исключение, а затем возвращает истину или ложь. Но я слышал, что какое-то оборудование вызовет исключение только один раз за попытку записи на одну страницу или что-то в этом роде.

Разве вы не можете использовать VirtualAlloc без MEM_COMMIT, поэтому вы просто резервируете адреса виртуальной памяти. Затем, когда вы действительно захотите использовать память, снова вызовите VirtualAlloc для выполнения фиксации. Поскольку вы уже зарезервировали страницы, у вас должна быть возможность фиксировать их непрерывно.

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

1 голос
/ 24 мая 2009

Ах, хорошо. В таком случае вы слышали о большой области памяти, я думаю, что это обходной путь Microsoft / решение вашей проблемы.

Обычно, если у вас VirtualAlloc больше 2 мегабайт, он попадает в большую область памяти виртуальной памяти, и это позволяет вам превысить ограничение в 32 МБ.

Здесь довольно хорошее обсуждение того, как все это работает:
http://msdn.microsoft.com/en-us/library/ms836325.aspx

Я сам использовал его на предыдущем продукте, и он помог мне.

...