全面介绍Windows内存管理机制及C++内存分配实例之虚拟内存(3)

来源:互联网 发布:淘宝交易资金保障 编辑:程序博客网 时间:2024/05/16 14:33
 

第一,分配进程虚拟空间:

VirtualAlloc (PVOID 开始地址,SIZE_T 大小,DWORD 类型,DWORD 保护属性)

“开始地址”可以是NULL,由系统分配进程空间;“类型”是MEM_RESERVE|MEM_PHYSICAL;“保护属性”只能是

PAGE_READWRITE。

MEM_PHYSICAL指的是区域将受物理存储器的支持。

第二,你要计算出分配的页面数目PageCount:

利用本文第二节的GetSystemInfo可以计算出来。

第三,分配物理内存页面:

AllocateUserPhysicalPages (HANDLE 进程句柄,SIZE_T 页数,ULONG_PTR 页面指针数组)

进程句柄可以用GetCurrentProcess()获得;页数是刚计算出来的页数PageCount;页面数组指针unsigned long* Array[PageCount]。

系统会将分配结果存进这个数组。

第四,将物理内存与虚拟空间进行映射:

MapUserPhysicalPages (PVOID 开始地址,SIZE_T 页数,ULONG_PTR 页面指针数组)

“开始地址”是第一步分配的空间;

这样的话,虚拟地址就可以使用了。

如果“页面指针数组”是NULL,则取消映射。

第五,释放物理页面

FreeUserPhysicalPages (HANDLE 进程句柄,SIZE_T 页数,ULONG_PTR 页面指针数组)

这个除了释放物理页面外,还会取消物理页面的映射。

第六,释放进程空间

VirtualFree (PVOID 开始地址,0,MEM_RELEASE)

C++程序:

首先,在登录用户有了Lock Pages in Memory权限以后,还需要调用Windows API激活这个权限。

BOOL VirtualMem::LoggedSetLockPagesPrivilege ( HANDLE hProcess,BOOL bEnable)                     

{

            struct {

                        DWORD Count;//数组的个数

                        LUID_AND_ATTRIBUTES Privilege [1];} Info;

            HANDLE Token;

            //打开本进程的权限句柄

            BOOL Result = OpenProcessToken ( hProcess,

                        TOKEN_ADJUST_PRIVILEGES,

                        & Token);

            If (Result!= TRUE )

            {

                        printf( "Cannot open process token.\n" );

                        return FALSE;

            }

            //我们只改变一个属性

            Info.Count = 1;

            //准备激活

            if( bEnable )

                    Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;

            else

                        Info.Privilege[0].Attributes = 0;

            //根据权限名字找到LGUID

            Result = LookupPrivilegeValue ( NULL,

                        SE_LOCK_MEMORY_NAME,

                        &(Info.Privilege[0].Luid));

            if( Result != TRUE )

            {

                        printf( "Cannot get privilege for %s.\n", SE_LOCK_MEMORY_NAME );

                        return FALSE;

            }

            // 激活Lock Pages in Memory权限

Result = AdjustTokenPrivileges ( Token, FALSE,(PTOKEN_PRIVILEGES) &Info,0, NULL, NULL);

            if( Result != TRUE )

            {

                        printf ("Cannot adjust token privileges (%u)\n", GetLastError() );

                        return FALSE;

            }

            else

            {

                        if( GetLastError() != ERROR_SUCCESS )

                        {

                                     printf ("Cannot enable the SE_LOCK_MEMORY_NAME privilege; ");

                                    printf ("please check the local policy.\n");

                                    return FALSE;

                        }

            }

            CloseHandle( Token );

            return TRUE;

}

分配100M虚拟空间:

PVOID pVirtual=VirtualAlloc(NULL,100*1024*1024,MEM_RESERVE|MEM_PHYSICAL,PAGE_READWRITE);

            if(pVirtual==NULL)

                        cout<<"没有那么大连续进程空间!"<<endl;

            MEMORYSTATUS memStatusVirtual5;

            GlobalMemoryStatus(&memStatusVirtual5);

            cout<<"虚拟内存分配:"<<endl;

             cout<<"减少物理内存="<<memStatusVirtual4.dwAvailPhys-memStatusVirtual5.dwAvailPhys<<endl

            cout<<"减少可用页文件="<<memStatusVirtual4.dwAvailPageFile-                                                     memStatusVirtual5.dwAvailPageFile<<endl;

           cout<<"减少可用进程空间="

                   <<memStatusVirtual4.dwAvailVirtual-memStatusVirtual5.dwAvailVirtual<<endl<<endl;

结果如下:

可以看见,只分配了进程空间,没有分配物理内存。

分配物理内存:

ULONG_PTR pages=(ULONG_PTR)100*1024*1024/sysInfo.dwPageSize;

            ULONG_PTR *frameArray=new ULONG_PTR[pages];

            //如果没激活权限,是不能调用这个方法的,可以调用,但是返回FALSE

BOOL flag=AllocateUserPhysicalPages(GetCurrentProcess(),

&pages,frameArray);

            if(flag==FALSE)

                        cout<<"分配物理内存失败!"<<endl;

            MEMORYSTATUS memStatusVirtual6;

            GlobalMemoryStatus(&memStatusVirtual6);

            cout<<"物理内存分配:"<<endl;

cout<<"减少物理内存="<<memStatusVirtual5.dwAvailPhys-memStatusVirtual6.dwAvailPhys<<endl

cout<<"减少可用页文件="<<memStatusVirtual5.dwAvailPageFile-memStatusVirtual6.dwAvailPageFile<<endl;

cout<<"减少可用进程空间="<<memStatusVirtual5.dwAvailVirtual-memStatusVirtual6.dwAvailVirtual<<endl<<endl;

结果如下:

减少物理内存分配:

减少物理内存=105037824

减少可用页文件=104976384

减少可用进程空间=1048576

分配了物理内存,可能分配时需要进程空间管理。

物理内存映射进程空间:

int* pVInt=(int*)pVirtual;

            //pVInt[0]=10;这时候访问会出错

            flag=MapUserPhysicalPages(pVirtual,1,frameArray);

            if(flag==FALSE)

                        cout<<"映射物理内存失败!"<<endl;

            MEMORYSTATUS memStatusVirtual7;

            GlobalMemoryStatus(&memStatusVirtual7);

            cout<<"物理内存分配:"<<endl;

cout<<"减少物理内存="<<memStatusVirtual6.dwAvailPhys-memStatusVirtual7.dwAvailPhys<<endl

cout<<"减少可用页文件="<<memStatusVirtual6.dwAvailPageFile-memStatusVirtual7.dwAvailPageFile<<endl;

cout<<"减少可用进程空间="

<<memStatusVirtual6.dwAvailVirtual-memStatusVirtual7.dwAvailVirtual<<endl<<endl;

结果如下:

物理内存分配:

减少物理内存=0

减少可用页文件=0

减少可用进程空间=0

这个过程没有损失任何东西。

看看第一次映射和第二次映射的值:

pVInt[0]=10;

            cout<<"第一次映射值="<<pVInt[0]<<endl;

                        flag=MapUserPhysicalPages(pVirtual,1,frameArray+1);

            if(flag==FALSE)

                        cout<<"映射物理内存失败!"<<endl;

            pVInt[0]=21;

            cout<<"第二次映射值="<<pVInt[0]<<endl;

            flag=MapUserPhysicalPages(pVirtual,1,frameArray);

            if(flag==FALSE)

                        cout<<"映射物理内存失败!"<<endl;

             cout<<"再现第一次映射值="<<pVInt[0]<<endl;

结果如下:

第一次映射值=10

第二次映射值=21

再现第一次映射值=10

可以看出,第二次映射的值没有覆盖第一次映射的值,也就是说,用同一个进程空间地址可以取出两份数据,这样的话,相当于进程的地址空间增大了。(完)

原创粉丝点击