14 虚拟内存一
【文起】蟹儿回家了,喉咙还有点儿不舒服,舍不得。想跟她一起过春节,奋斗。
虚拟内存其实只是虚拟出来的一个地址空间,不是真正的内存。是为了提高程序加载效率而产生的一种技术。
1、 系统信息:
操作系统的值都是根据主机来的,比如页面大小,分配粒度的大小等。我们可以通过GetSystemInfo函数来检索主机相关的值。可以获取到的值包括:CPU类型以及型号等;CPU页面大小;CPU数目。通过该函数,可以写出如下小程序
、
void CSystemInfoDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
TCHAR szCpuArch[64] = _T("(unknown)");
TCHAR szCpuLevel[64] = _T("(unknown)");
TCHAR szCpuRev[64] = _T("(unknown)");
TCHAR szBuf[50];
TCHAR szLine[50] = _T("豆浆&&蟹蟹");
//获取CPU类型
switch(sysinfo.wProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_INTEL://interl
{
lstrcpy(szCpuArch,_T("Intel"));
//CPU型号
switch (sysinfo.wProcessorLevel)
{
case 3:
case 4:
wsprintf(szCpuLevel,_T("%80%c86"),sysinfo.wProcessorLevel + '0');
wsprintf(szCpuRev,_T("%c%d"),HIBYTE(sysinfo.wProcessorRevision) + _T('A'),
LOBYTE(sysinfo.wProcessorRevision));
break;
case 5:
wsprintf(szCpuLevel,_T("Pentium"));
wsprintf(szCpuRev,_T("Model %d,Stepping %d"),
HIBYTE(sysinfo.wProcessorRevision),LOBYTE(sysinfo.wProcessorRevision));
break;
case 6:
wsprintf(szCpuLevel,_T("Pentium Pro or Pentium II"));
wsprintf(szCpuRev,_T("Model %d,Stepping %d"),
HIBYTE(sysinfo.wProcessorRevision),LOBYTE(sysinfo.wProcessorRevision));
break;
}
break;
}
case PROCESSOR_ARCHITECTURE_ALPHA:
lstrcpy(szCpuArch,_T("Alpha"));
wsprintf(szCpuLevel,_T("%d"),sysinfo.wProcessorLevel);
wsprintf(szCpuRev,_T("Model %c,Pass %d"),
HIBYTE(sysinfo.wProcessorRevision) + _T('A'),
LOBYTE(sysinfo.wProcessorRevision));
break;
case PROCESSOR_ARCHITECTURE_IA64:
lstrcpy(szCpuArch,_T("IA-64"));
wsprintf(szCpuLevel,_T("%d"),sysinfo.wProcessorLevel);
wsprintf(szCpuRev,_T("Model %c,Pass %d"),
HIBYTE(sysinfo.wProcessorRevision) + _T('A'),
LOBYTE(sysinfo.wProcessorRevision));
break;
case PROCESSOR_ARCHITECTURE_ALPHA64:
lstrcpy(szCpuArch,_T("ALPHA-64"));
wsprintf(szCpuLevel,_T("%d"),sysinfo.wProcessorLevel);
wsprintf(szCpuRev,_T("Model %c,Pass %d"),
HIBYTE(sysinfo.wProcessorRevision) + _T('A'),
LOBYTE(sysinfo.wProcessorRevision));
break;
case PROCESSOR_ARCHITECTURE_UNKNOWN:
default:
wsprintf(szCpuArch,_T("Unknown"));
}
SetDlgItemText(IDC_STATIC_PROCESS_ARCHITECTURE,szCpuArch);
SetDlgItemText(IDC_STATIC_PROCESS_LEVEL,szCpuLevel);
SetDlgItemText(IDC_STATIC_PROCESS_REVISION,szCpuRev);
SetDlgItemInt(IDC_STATIC_PAGE_SIZE,sysinfo.dwPageSize);//CPU页面大小
_stprintf(szBuf,_T("%p"),sysinfo.lpMinimumApplicationAddress);
SetDlgItemText(IDC_STATIC_MIN_ADDRESS,szBuf);
_stprintf(szBuf,_T("%p"),sysinfo.lpMaximumApplicationAddress);
SetDlgItemText(IDC_STATIC_MAX_ADDRESS,szBuf);
_stprintf(szBuf,_T("0x%016I64x"),(__int64)sysinfo.dwActiveProcessorMask);
SetDlgItemText(IDC_STATIC_PROCESSOR_MASK,szBuf);
SetDlgItemInt(IDC_STATIC_PROCESS_NUMBER,sysinfo.dwNumberOfProcessors);//CPU个数
SetDlgItemInt(IDC_STATIC_ALLOCATION_GRANULARITY,sysinfo.dwAllocationGranularity);
wsprintf(&szLine[_tcslen(szLine)],_T("%u"),ul_count++);
SetDlgItemText(IDC_STATIC_COUNT,szLine);
CDialog::OnTimer(nIDEvent);
}
2、 虚拟内存的状态:
Windows中,可以通过GlobalMemoryStatus检索冠旭当前内存状态的动态信息。这个程序比较简单,不举例。
3、 确定地址空间的状态:
虚拟内存通常是由固定大小的块来实现的,在WIN32中这些块称为“页”,每页大小为4,096字节。在IntelCPU结构中,通过在一个控制寄存器中设置一位来启用分页。启用分页时CPU并不能直接访问内存,对每个地址要经过一个映射进程,通过一系列称作“页表”的查找表把虚拟内存地址映射成实际内存地址。通过使用硬件地址映射和页表WIN32可使虚拟内存即有好的性能而且还提供保护。利用处理器的页映射能力,操作系统为每个进程提供独立的从逻辑地址到物理地址的映射,使每个进程的地址空间对另一个进程完全不可见。
内存页面可以有三种状态:未用(Free)、保留(Reserved)和提交(Committed)。一个未用的页面是指该页面未被保留或是提交,对一个进程来讲一个未用的页面是不可访问的,访问这样的页面将导致访问违例。进程可以要求系统保留一些页面以备后用,系统返回一段保留的地址给进程,但是这些地址同样是不可访问的,进程若想使用这段地址空间,使用必须先提交。只有一个提交的页面才是一个真正可以访问的页面。不过你提交了一个页面,系统并不会马上分配物理页面,只有在该页面第一次被访问到时,系统才会分配页面并初始化。另外,这三个状态的两两之间都是可以相互转化的。
通过下面的函数来查询虚拟内存的状态。
DWORD VirtualQuery(LPCVOID pvAddress, PMEMORY_BASIC_INFORMATION pmbi,DWORD deLength);
DWORD VirtualQueryEx(HANDLE hProcess,LPCVOID pvAddress, PMEMORY_BASIC_INFORMATION pmbi,DWORD deLength);