【问题标题】:Unit Testing for x86 LargeAddressAware compatibilityx86 LargeAddressAware 兼容性的单元测试
【发布时间】:2014-05-31 14:22:35
【问题描述】:

对于 win32 可执行文件 (x86),我们可以设置 LargeAddressAware 标志,以便它在 x64 Windows 上运行时可以访问 4 GB(而不是仅 2 GB)的虚拟地址空间。
这看起来非常吸引人。但是,其中存在风险。
例如参见:Drawbacks of using /LARGEADDRESSAWARE for 32 bit Windows executables?

让我们继续配置正在执行一些单元测试的系统,将系统范围的注册表开关AllocationPreference 设置为MEM_TOP_DOWN
应该这样做,不是吗?

没有!
问题是 Visual Studio 的 x86“测试运行器”(执行引擎)本身没有启用 LAA。
这个父进程只会看到“较低”的 2 GB VAS,我们要测试的模块也是如此。

来自 VS2013.1 的示例

  • mstest.exe 产生 QTAgent32.exe
  • vstest.console.exe 产生 vstest.executionengine.x86.exe

他们都启用 LAA!

那么推荐使用启用 LAA 的 x86 测试运行器的方法是什么?


这里有一个小代码 sn-p(VS 单元测试,csharp)来检查 LAA 执行环境。
除非它成功,否则您的测试环境适合让您的单元测试集(也)涵盖与 LAA 的兼容性:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestCheckEnv32LAA
{
    [TestClass]
    public class CheckEnv32LAA
    {
        #region [Native DLL import]

        [Flags()]
        public enum AllocationType : uint
        {
            COMMIT = 0x1000,
            RESERVE = 0x2000,
            RESET = 0x80000,
            LARGE_PAGES = 0x20000000,
            PHYSICAL = 0x400000,
            TOP_DOWN = 0x100000,
            WRITE_WATCH = 0x200000
        }

        [Flags()]
        public enum MemoryProtection : uint
        {
            EXECUTE = 0x10,
            EXECUTE_READ = 0x20,
            EXECUTE_READWRITE = 0x40,
            EXECUTE_WRITECOPY = 0x80,
            NOACCESS = 0x01,
            READONLY = 0x02,
            READWRITE = 0x04,
            WRITECOPY = 0x08,
            GUARD_Modifierflag = 0x100,
            NOCACHE_Modifierflag = 0x200,
            WRITECOMBINE_Modifierflag = 0x400
        }

        [StructLayout(LayoutKind.Sequential)]
        struct MEMORYSTATUSEX
        {
            public uint dwLength;
            public uint dwMemoryLoad;
            public ulong ullTotalPhys;
            public ulong ullAvailPhys;
            public ulong ullTotalPageFile;
            public ulong ullAvailPageFile;
            public ulong ullTotalVirtual;
            public ulong ullAvailVirtual;
            public ulong ullAvailExtendedVirtual;
        }

        [DllImport("kernel32.dll")]
        extern static void GlobalMemoryStatusEx(ref MEMORYSTATUSEX status);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern UIntPtr VirtualAlloc(UIntPtr lpAddress, UIntPtr dwSize,
        AllocationType flAllocationType, MemoryProtection flProtect);

        #endregion

        public CheckEnv32LAA()
        {
        }

        [TestMethod]
        public void CheckEnvironment32LAA()
        {
            // check for a suitable environment to test modules for compatibility with LargeAddressAware (LAA):
            // 1) OS must be x64
            // 2) test runner must be x86
            // 3) test runner must be LAA enabled itself
            // 4) memory allocation (with manual TopDown flag) must happen beyond the 2 GB boundary
            // 5) memory allocation (with default settings) must happen beyond the 2 GB boundary
            //
            // RE 3) this requirement is true for "regular" unit tests (to test DLL modules). it does not apply
            // for any tests spawning the application (EXE) to be tested as a separate process.
            // 
            // RE 5) a failure indicates the following registry switch has not been set:
            // [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management]
            // "AllocationPreference"=dword:00100000
            //
            // see:
            // https://stackoverflow.com/questions/2288728/

            String sParentProcName = Process.GetCurrentProcess().MainModule.FileName;

            //CHECK_1
            Assert.IsTrue(Environment.Is64BitOperatingSystem, "Test is not executing on x64 OS");

            //CHECK_2
            Assert.IsFalse(Environment.Is64BitProcess, "Test runner is not x86: " + sParentProcName);

            //CHECK_3
            MEMORYSTATUSEX tmpStatus = new MEMORYSTATUSEX();
            tmpStatus.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
            tmpStatus.ullTotalPhys = 0;
            GlobalMemoryStatusEx(ref tmpStatus);
            ulong uVM = tmpStatus.ullTotalVirtual;
            Assert.IsTrue(uVM > 0x80000000, "Test runner is not LAA enabled (max: " + uVM / (1024 * 1024) + "): " + sParentProcName);
            Assert.IsTrue(uVM <= 0x100000000, "Test runner is not x86 (max: " + uVM / (1024 * 1024) + "): " + sParentProcName);

            //CHECK_4
            UIntPtr pMem = UIntPtr.Zero;
            ulong uAddress = 0;
            pMem = VirtualAlloc(UIntPtr.Zero, (UIntPtr)1024, AllocationType.RESERVE | AllocationType.TOP_DOWN, MemoryProtection.READWRITE);
            uAddress = (ulong)pMem;
            Assert.IsTrue(uAddress > 0x80000000, "Test runner is not LAA enabled (highest: " + uAddress / (1024 * 1024) + "): " + sParentProcName);

            //CHECK_5
            pMem = VirtualAlloc(UIntPtr.Zero, (UIntPtr)1024, AllocationType.RESERVE, MemoryProtection.READWRITE);
            uAddress = (ulong)pMem;
            Assert.IsTrue(uAddress > 0x80000000, "System-wide MEM_TOP_DOWN is not set (allocated at: " + uAddress / (1024 * 1024) + ")");
        }
    }
}

【问题讨论】:

  • 请注意,4 GB 地址空间仅适用于 64 位系统。在 32 位系统上,大地址感知应用程序只能寻址 3 GB。
  • 用editbin.exe给EXE打补丁是唯一实用的解决方案。

标签: windows unit-testing visual-studio-2013 mstest virtual-address-space


【解决方案1】:

到目前为止,我只遇到过将问题中列出的 Microsoft 二进制文件弄乱的建议(即使用 editbin.exe 手动“修补”它们)。但这有以下缺点:

  • 为 Visual Studio 安装任何未来的服务包后,我需要重复修补
  • 我无法再并行测试:“常规”x86 和“扩展”x86 与 LAA

微软似乎必须实施一个适当的长期解决方案?:
http://visualstudio.uservoice.com/forums/196039-microsoft-test-tools/suggestions/5781437

【讨论】:

    猜你喜欢
    • 2020-12-16
    • 1970-01-01
    • 1970-01-01
    • 2021-05-01
    • 1970-01-01
    • 2021-04-11
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多