{"id":109204,"date":"2023-12-29T07:00:00","date_gmt":"2023-12-29T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109204"},"modified":"2023-12-29T08:22:07","modified_gmt":"2023-12-29T16:22:07","slug":"20231229-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231229-00\/?p=109204","title":{"rendered":"How to allocate address space with a custom alignment or in a custom address region"},"content":{"rendered":"<p>Windows 10 version 1803 added the ability to request specific alignment and address region requirements when creating address space mappings either for virtual memory (<code>Virtual\u00adAlloc2<\/code>) or file mappings (<code>Map\u00adView\u00adOf\u00adFile3<\/code>). These new functions let you pass a <code>MEM_<wbr \/>ADDRESS_<wbr \/>REQUIREMENTS<\/code> structure which can specify additional constraints:<\/p>\n<ul>\n<li><code>Lowest\u00adStarting\u00adAddress<\/code>: The lowest address in the region.<\/li>\n<li><code>Highest\u00adEnding\u00adAddress<\/code>: The highest address in the region.<\/li>\n<li><code>Alignment<\/code>: The desired alignment.<\/li>\n<\/ul>\n<p>If any field is zero, then the system uses whatever value it normally would have. For example, if you say that the alignment is zero, then the memory will be aligned on the allocation granularity (for normal-sized pages) or the large page granularity (for large pages).<\/p>\n<p>Here are some sample usages:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>Scenario<\/th>\n<th>Lowest\u00adStarting\u00adAddress<\/th>\n<th>Highest\u00adEnding\u00adAddress<\/th>\n<th>Alignment<\/th>\n<\/tr>\n<tr>\n<td>Align to multiple of <var>N<\/var><\/td>\n<td align=\"right\">0<\/td>\n<td align=\"right\">0<\/td>\n<td align=\"right\"><var>N<\/var><\/td>\n<\/tr>\n<tr>\n<td>Below 4GB<\/td>\n<td align=\"right\">0<\/td>\n<td style=\"font-size: 80%;\" align=\"right\"><code>0x00000000`FFFFFFFF<\/code><\/td>\n<td align=\"right\">0<\/td>\n<\/tr>\n<tr>\n<td>Above 4GB<\/td>\n<td style=\"font-size: 80%;\" align=\"right\"><code>0x00000001`00000000<\/code><\/td>\n<td align=\"right\">0<\/td>\n<td align=\"right\">0<\/td>\n<\/tr>\n<tr>\n<td>At 1MB boundary<br \/>\nbetween 2GB and 4GB<\/td>\n<td style=\"font-size: 80%;\" align=\"right\"><code>0x00000000`80000000<\/code><\/td>\n<td style=\"font-size: 80%;\" align=\"right\"><code>0x00000000`FFFFFFFF<\/code><\/td>\n<td style=\"font-size: 80%;\" align=\"right\"><code>0x00000000`00100000<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Note that the <code>Highest\u00adEnding\u00adAddress<\/code> is endpoint-inclusive. In other words, it is the highest address in the region, not the highest address <i>plus one<\/i>.<\/p>\n<p>Here&#8217;s how you pass the <code>MEM_<wbr \/>ADDRESS_<wbr \/>REQUIREMENTS<\/code>:<\/p>\n<pre>MEM_ADDRESS_REQUIREMENTS requirements = {0};\r\n\r\nrequirements.LowestStartingAddress = \u27e6 value \u27e7;\r\nrequirements.HighestStartingAddress = \u27e6 value \u27e7;\r\nrequirements.Alignment = \u27e6 value \u27e7;\r\n\r\nMEM_EXTENDED_PARAMETER param = {0};\r\nparam.Type = MemExtendedParameterAddressRequirements;\r\nparam.Pointer = &amp;requirements;\r\n\r\nauto result = VirtualAlloc2(nullptr, nullptr,\r\n        size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE,\r\n        &amp;param, 1);\r\n<\/pre>\n<p>The <code>Virtual\u00adAlloc2<\/code> function takes a pointer to an array of <code>MEM_<wbr \/>EXTENDED_<wbr \/>PARAMETER<\/code> structures, but since we have only one, we just pass the address of a single object and tell the system that we have an array of only one element.<\/p>\n<p>Note that you cannot combine non-default <code>MEM_<wbr \/>ADDRESS_<wbr \/>REQUIREMENTS<\/code> with an explicit <code>Base\u00adAddress<\/code>. If you pass an explicit base address, then you are saying, &#8220;I want the memory to be exactly here; I don&#8217;t want the system to choose for me.&#8221; Under those conditions, it&#8217;s meaningless to tell the system &#8220;And here is how I&#8217;d like you to choose the address for me.&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Some new powers to guide the allocation.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-109204","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Some new powers to guide the allocation.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109204","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=109204"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109204\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=109204"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109204"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109204"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}