目录
一、进程概述
进程:正在运行的程序
程序是计算机指令的集合,它以文件的形式存储在磁盘上,而进程通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动.一个程序可以对应多个进程
进程是资源申请,高度和独立运行的单位,因此,它使用系统中的运行资源,而程序不能申请系统资源,不能被系统高度也不能作为独立运行的单位,因此它不占系统运行资源.
进程组成:
<1> 操作系统用来管理进行的内核对象
内核对象也是系统用来存放关于进程的统计信息的地方.内核对象是操作系统内部分配的一个内存块,该内存块是一种数据结构,其成员负责维护该对象的各种信息.
<2> 地址空间
它包含所有可执行模块或DLL模块的代码和数据.另外,它也包含动态内存分配的空间,例如线程的栈和堆分配空间
进程从来不执行任何东西,它只是纯种的容器,若要使进行完成某项操作,它必须拥有一个在它的环境中运行的纯种,此线程负责执行包含在进程的地址空间的中的代码.也就是,真正完成代码执行的是线程,而进程只是纯种的容器,或者说是线程的执行环境.
子进程:还是一个进程,子进程指的是由另一进程(对应称之为父进程)所创建的进程。
子进程的线程既可以在父进程终止之后执行我们的代码;也可以在父进程运行的过程中执行代码。
当进程创建时,以下是更详细的过程说明:
-
程序加载:操作系统从磁盘上读取程序的可执行文件,并将其加载到内存中。此过程包括分配内存空间、读取可执行文件的内容,并将其映射到进程的地址空间。
-
设置进程环境:操作系统为新进程创建一个独立的进程环境。这包括分配一个唯一的进程ID(Process ID)和主线程ID(Thread ID),以及为进程分配用于存储全局变量和堆栈的内存空间。
-
分配资源:操作系统为新进程分配必要的资源。这可能包括文件描述符、I/O设备、内存映射文件、共享内存等。
-
上下文初始化:操作系统为新进程创建一个初始的上下文环境。这包括设置进程的寄存器(如程序计数器、堆栈指针等),以及初始化进程的虚拟内存映射表。
-
加载动态链接库:如果程序依赖于动态链接库(DLL),操作系统会将相关的DLL加载到进程的地址空间,以便程序可以调用其中的函数和共享代码。
-
启动主线程:操作系统会创建进程的主线程,并将其设置为就绪状态,以便可以开始执行程序的代码。
-
执行入口点:主线程会开始执行程序的入口点(Entry Point),通常是程序的main函数。程序的执行从入口点开始,按照指令顺序逐步执行。
当进程终止时,以下是更详细的过程说明:
-
执行结束:当进程执行完所有的指令或者遇到终止指令时,进程的执行结束。
-
释放资源:操作系统会回收进程所占用的资源,包括内存空间、文件描述符、打开的文件、网络连接等。这样可以确保系统中的资源不被浪费和滥用。
-
更新进程状态:操作系统会更新进程的状态信息,包括退出码(Exit Code)和资源使用统计等。这些信息可以供其他进程或系统监控程序使用。
-
关闭进程句柄:如果其他进程持有该进程的句柄(如父进程或其他相关进程),操作系统会关闭这些句柄,以确保资源的正确释放。
-
终止主线程和进程:操作系统会终止进程的主线程,并将进程标记为已终止。这样,操作系统就可以回收与该进程相关的资源,并从进程列表中移除该进程。
二、创建进程相关API
上面两个16位系统使用的,使用简单,仍然在重要使用;第三个CreateProcess要穿10个参数,CreateProcess功能最为齐全;
Winexec
功能:主要运行EXE文件;即创建一个进程
UINT WINAPI WinExec(
_In_ LPCSTR lpCmdLine,
_In_ UINT uCmdShow
);
参数说明:
- 参数一:.exe 可执行文件的路径
- 参数二:窗口显示状态
参数一会自动按照一定顺序检索文件:
搜索路径的顺序如下:
- 当前目录:首先,系统会在当前工作目录中搜索文件,即调用WinExec函数的程序所在的目录。
- 系统目录(System32):如果文件没有在当前目录中找到,系统会搜索系统目录(通常是C:\Windows\System32)。系统会自动将系统目录添加到搜索路径中。
- Windows目录:如果文件在系统目录中仍未找到,系统会搜索Windows目录(通常是C:\Windows)。系统同样会自动将Windows目录添加到搜索路径中。
- 环境变量Path中指定的目录:如果文件在以上路径中仍未找到,系统会按照环境变量Path中指定的路径顺序进行搜索。Path变量中包含一系列目录路径,以分号 (;) 分隔。
参数二常用的显示窗口状态:
- SW_SHOW:显示窗口,以当前大小和位置显示。
- SW_HIDE:隐藏窗口,执行过程在后台运行,不显示窗口。
程序想要隐藏好自己,把自己加入启动项这有点傻,应该加入服务启动与内存常驻。
注意:启动cmd的时候,需要两个才能填命令行
测试样例
启动进程;拷贝文件;修改注册表。
ShellExecute
功能:ShellExecute的功能是运行一个外部程序(或者是打开一个已注册的文件、打开一个目录、打印一个文件等等)并对外部程序有一定的控制。有几个API函数都可以实现这些功能,但是在大多数情况下ShellExecute是更多的被使用的,同时它并不是太复杂。其实就是加强版的WinExec
SHSTDAPI_(HINSTANCE) ShellExecuteW(_In_opt_ HWND hwnd,
_In_opt_ LPCWSTR lpOperation,
_In_ LPCWSTR lpFile,
_In_opt_ LPCWSTR lpParameters,
_In_opt_ LPCWSTR lpDirectory,
_In_ INT nShowCmd
);
参数说明:
- 参数一:指定父窗口句柄,没有则为空
- 参数二:指定动作,操作对象都是参数 lpfile
- 参数三:可以是网址,可执行
- 参数四:用于指定默认目录,若lpFile参数是一个可执行文件,则此参数指定命令行参数
- 参数五:用于指定程序窗口初始显示方式。
关于参数二的动作:
- NULL, 默认操作"open"
- Edit, 打开文件类型的默认程序
- explore, 打开文件夹
- find, 打开查找窗口
- open。 打开文件或文件夹
- print, 打印机界面(lpfile参数指定的文件)
- runes, 管理员权限
参数五窗口显示方式:
#define SW_HIDE 0 /*隐藏窗体,并激活另一个窗体*/
#define SW_SHOWNORMAL 1 /*与SW_RESTORE相同*/
#define SW_SHOWMINIMIZED 2 /*激活并以最小化的形式显示窗体*/
#define SW_SHOWMAXIMIZED 3 /*激活并以最大化的形式显示窗体*/
#define SW_MAXIMIZE 3 /*最大化指定的窗体*/
#define SW_SHOWNOACTIVATE 4 /*以上次的状态显示指定的窗体,但不激活它*/
#define SW_SHOW 5 /*激活窗体,并将其显示在当前的大小和位置上*/
#define SW_MINIMIZE 6 /*最小化指定的窗体,并激活另一个窗体*/
#define SW_SHOWMINNOACTIVE 7 /*以最小化形式显示指定的窗体,但不激活它*/
#define SW_SHOWNA 8 /*以当前的状态显示指定的窗体,但不激活它*/
#define SW_RESTORE 9 /*以原本的大小和位置,激活并显示指定的窗体*/
#define SW_SHOWDEFAULT 10 /*设置显示的状态由STARTUPINFO结构体指定*/
测试代码:
ShellExecute(NULL, "open", "E:\\CR41\\第2阶段\\Windows\\04-进程和进程遍历\\Test\\Test.txt", NULL, NULL, SW_SHOWNORMAL);
ShellExecute(NULL, "open", "www.baidu.com/s?wd=\"拼音\"", NULL, NULL, SW_SHOW);
ShellExecute(NULL, "explore", "E:\\CR41\\第2阶段\\Windows\\04-进程和进程遍历\\Test", NULL, NULL, SW_SHOWNORMAL);
ShellExecute(NULL, "print", "E:\\CR41\\第2阶段\\Windows\\04-进程和进程遍历\\Test\\Test.txt", NULL, NULL,SW_SHOW);
ShellExecute(NULL, "open", "calc.exe", NULL, NULL, SW_SHOW);
CreateProcess
用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件。
BOOL WINAPI CreateProcessW(
_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);
参数说明:
- lpApplicationName:绝对路径,相对路径,不会自动搜索
- lpCommandLine:如果需要搜索,参数1填NULL,支持命令行参数。
- lpProcessAttributes:填NULL,暂时不考虑
- lpThreadAttributes:填NULL,暂时不考虑
- bInheritHandles:填TRUE和FALSE都可以
- dwCreationFlags:创建标志,从表中选,默认给0
- lpEnvironment:指向新的环境块的指针 ,默认NULL
- lpCurrentDirectory:指向新的环境块的指针 ,默认NULL
- lpStartupInfo:指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
- lpProcessInformation:指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体
关于参数 lpApplicationName
一个指向NULL终止的字符串,用来指定可执行程序的名称。该名称可以是该程序的完整路径和文件名,也可以是部分名称。如果是后者,CreateProcess函数就在当前路径下搜索可执行文件名,但不会使用搜索路径进行搜索。注意:一定要加上扩展名,系统不会自动假设文件名有一个“.exe”扩展名。
关于dwCreationFlags
- CREATE_DEFAULT_ERROR_MODE (0x04000000):使用默认的错误模式。
- CREATE_NEW_CONSOLE (0x00000010):新进程拥有一个新的控制台窗口。
- CREATE_NEW_PROCESS_GROUP (0x00000200):将新进程创建为一个新的进程组。
- CREATE_NO_WINDOW (0x08000000):新进程不创建窗口,即在后台执行。
- CREATE_PROTECTED_PROCESS (0x00040000):创建一个受保护的进程。
- CREATE_PRESERVE_CODE_AUTHZ_LEVEL (0x02000000):继承父进程的代码授权级别。
- CREATE_SEPARATE_WOW_VDM (0x00000800):创建一个独立的虚拟DOS机(VDM)进程。
- CREATE_SHARED_WOW_VDM (0x00001000):创建一个共享的虚拟DOS机(VDM)进程。
- CREATE_SUSPENDED (0x00000004):创建进程后暂停进程的执行。
- DEBUG_ONLY_THIS_PROCESS (0x00000002):生成一个仅供当前进程调试使用的进程。
- DEBUG_PROCESS (0x00000001):生成一个可以由调试器调试的进程。
- DETACHED_PROCESS (0x00000008):生成一个无控制台的进程。
关于lpStartupInfo
创建新进程主窗口结构体
typedef struct _STARTUPINFO
{
DWORD cb; //包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,它可用作版本控制手段.应用程序必须将cb初始化为sizeof(STARTUPINFO)
PSTR lpReserved; //保留。必须初始化为NULL
PSTR lpDesktop; //用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与指定的桌面相关联。如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。如果lpDesktop是NULL(这是最常见的情况 ),那么该进程将与当前桌面相关联
PSTR lpTitle; //用于设定控制台窗口的名称。如果lpTitle是NULL,则可执行文件的名字将用作窗口名.This parameter must be NULL for GUI or console processes that do not create a new console window.
DWORD dwX; //用于设定应用程序窗口相对屏幕左上角位置的x 坐标(以像素为单位)。
DWORD dwY; //对于GUI processes用CW_USEDEFAULT作为CreateWindow的x、y参数,创建它的第一个重叠窗口。若是创建控制台窗口的应用程序,这些成员用于指明相对控制台窗口的左上角的位置
DWORD dwXSize; //用于设定应用程序窗口的宽度(以像素为单位)
DWORD dwYSize; //子进程将CW_USEDEFAULT 用作CreateWindow 的nWidth、nHeight参数来创建它的第一个重叠窗口。若是创建控制台窗口的应用程序,这些成员将用于指明控制台窗口的宽度
DWORD dwXCountChars; //用于设定子应用程序的控制台窗口的宽度(屏幕显示的字节列)和高度(字节行)(以字符为单位)
DWORD dwYCountChars;
DWORD dwFillAttribute; //用于设定子应用程序的控制台窗口使用的文本和背景颜色
DWORD dwFlags; //请参见下一段和表4-7 的说明
WORD wShowWindow; //用于设定如果子应用程序初次调用的ShowWindow 将SW_*作为nCmdShow 参数传递时,该应用程序的第一个重叠窗口应该如何出现。本成员可以是通常用于ShowWindow 函数的任何一个SW_*标识符,除了SW_SHOWDEFAULT.
WORD cbReserved2; //保留。必须被初始化为0
PBYTE lpReserved2; //保留。必须被初始化为NULL
HANDLE hStdInput; //用于设定供控制台输入和输出用的缓存的句柄。按照默认设置,hStdInput 用于标识键盘缓存,hStdOutput 和hStdError用于标识控制台窗口的缓存
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
============================================ 使 用 =====================================
当Windows 创建新进程时,它将使用该结构的有关成员。大多数应用程序将要求生成的应用程序仅仅使用默认值。至少应将该结构中的所有成员初始化为零,然后将cb成员设置为该结构的大小:
STARTUPINFO StartupInfo;
char szCMDPath[255];
//配置隐藏窗口结构体
StartupInfo.cb=sizeof(STARTUPINFO);
StartupInfo.wShowWindow=SW_HIDE;
StartupInfo.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
StartupInfo.hStdInput=(HANDLE)listenFd;
StartupInfo.hStdOutput=(HANDLE)listenFd;
StartupInfo.hStdError=(HANDLE)listenFd;
//创建匿名管道
PROCESS_INFORMATION ProcessInfo;
//other operation
CreateProcess(NULL,szCMDPath,NULL,NULL,TRUE,0,NULL,NULL,&StartupInfo,&ProcessInfo);
==================================== dwFlags 使用标志及含义 ==========================================================
STARTF_USESIZE //使用dwXSize 和dwYSize 成员
STARTF_USESHOWWINDOW //使用wShowWindow 成员
STARTF_USEPOSITION //使用dwX 和dwY 成员
STARTF_USECOUNTCHARS //使用dwXCountChars 和dwYCount Chars 成员
STARTF_USEFILLATTRIBUTE //使用dwFillAttribute 成员
STARTF_USESTDHANDLES //使用hStdInput 、hStdOutput 和hStdError 成员
STARTF_RUN_FULLSCREEN //强制在x86 计算机上运行的控制台应用程序以全屏幕方式启动运行
指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。大多数应用程序都希望生成的应用程序只是使用默认值,最起码要全部初始化为0,再把cb成员设为此结构体的大小,如果没有清0,则新进程可能创建失败.
关于 lpProcessInformation
进程信息结构体
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;
这段代码定义了一个名为PROCESS_INFORMATION的结构体。它包含了以下成员:
- hProcess:进程的句柄(handle),用于操作和管理进程。
- hThread:线程的句柄(handle),用于操作和管理线程。
- dwProcessId:进程的ID(Process ID),用于唯一标识一个进程。
- dwThreadId:线程的ID(Thread ID),用于唯一标识一个线程。
通过CreateProcess函数创建新进程时,可以使用PROCESS_INFORMATION结构体来接收返回的进程信息。具体来说,hProcess成员用于获取新进程的句柄,hThread成员用于获取新进程的主线程句柄,dwProcessId成员用于获取新进程的ID,dwThreadId成员用于获取新进程的主线程ID。
测试代码
void CMFCApplication1Dlg::OnBnClickedBtn1()
{
// TODO: 在此添加控件通知处理程序代码
// TODO: 在此添加控件通知处理程序代码
STARTUPINFO si = {
NULL,//cb,指定结构的大小(以字节为单位)。
NULL,//保留。必须初始化为N U L L
NULL,//lpDesktop
/*用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与指定的桌面相关联。
如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。
如果l p D e s k t o p 是N U L L (这是最常见的情况),那么该进程将与当前桌面相关联*/
"HELLO!",//lpTitle
/* 对于控制台进程,如果创建了一个新的控制台窗口,这是在标题栏中显示的标题。
如果为空,则可执行文件的名称被用作窗口标题。对于不创建新控制台窗口的GUI或控制台进程,
此参数必须为NULL*/
300,300,//dwX,dwY
/*用于设定应用程序窗口在屏幕上应该放置的位置的x 和y 坐标(以像素为单位)。
若是创建控制台窗口的应用程序,这些成员用于指明控制台窗口的左上角*/
100,100,//dwXSize,dwYSize
/*用于设定应用程序窗口的宽度和长度(以像素为单位)若是创建控制台窗口的应用程序,
这些成员将用于指明控制台窗口的宽度*/
100,500,//dwXCountChars,dwYCountChars
//用于设定子应用程序的控制台窗口的宽度和高度(以字符为单位)注意:二者一样并不是矩形;
FOREGROUND_BLUE | BACKGROUND_GREEN,//dwFillAttribute
/*FOREGROUND_BLUE | FOREGROUND_GREEN
|FOREGROUND_RED | FOREGROUND_INTENSITY
|BACKGROUND_BLUE|BACKGROUND_GREEN
|BACKGROUND_RED|BACKGROUND_INTENSITY,*/
//用于设定子应用程序的控制台窗口使用的文本和背景颜色
STARTF_USEFILLATTRIBUTE | STARTF_USESIZE | STARTF_USECOUNTCHARS ,
//|STARTF_USESHOWWINDOW//窗口显示的方式,最大化最小化,
//| STARTF_USEPOSITION//dwX,dwY
//使用d w F i l l A t t r i b u t e 成员
//这是一个位字段,决定进程创建窗口时是否使用某些STARTUPINFO成员。可以指定以下值的任意组合:
//STARTF_USESIZE使用dwXSize和dwYSize 成员
//STARTF_USESHOWWINDOW使用wShowWindow 成员
//STARTF_USEPOSITION使用dwX和dwY 成员
//STARTF_USECOUNTCHARS使用dwXCountChars和dwYCount Chars 成员
//STARTF_USEFILLATTRIBUTE使用dwFillAttribute成员
//STARTF_USESTDHANDLES使用hStdInput、hStdOutput和hStdError成员
//STARTF_RUN_FULLSCREEN强制在x86计算机上运行的控制台应用程序以全屏幕方式启动运行
SW_SHOW,//见表
0,//保留; 必须为零
NULL, // 保留; 必须为NULL
//最后还有三个参数,忽略
//HANDLE hStdInput;
//HANDLE hStdOutput;
//HANDLE hStdError;
};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {};
//研究CreateProcess中的STARTUPINFO 中的成员的用法,并提供示例代码
::CreateProcess(NULL,//exe路径
"cmd.exe",//命令行参数
//"calc",
NULL, NULL, FALSE,//暂时不用
0,//默认
NULL,//环境遍历
NULL,//当前目录
&si,
&pi
);
}
void CProcessDlg::OnBnClickedButton3()
{
STARTUPINFO si = {};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {};
BOOL bRet = ::CreateProcess(
"E:\\CR41\\第2阶段\\Windows\\04-进程和进程遍历\\Process\\Debug\\Process - 副本.exe",//exe路径
NULL,//命令行参数
NULL,
NULL,
FALSE,
0,//创建标志,默认给0
NULL,//环境块,环境变量
NULL,//当前目录,工作目录
&si,
&pi
);
if (!bRet)
{
AfxMessageBox("创建进程失败");
}
}
但是CreateProcess 这样使用的话,不具备搜索路径的功能,也就是说lpApplicationName 不为空的话,不会自动搜索路径
如果在lpCommandLine参数中传递了一个可执行的文件名,并且没有包含路
径,lpApplicationName为空就会自动搜索路径。那么这时CreateProcess函数将按照以下顺序搜索可执行文件:
(1)应用程序被装载的目录。
(2)父进程的目录。
(3)32位Windows系统目录。可以使用GetSystemDirectory函数
来得到该目录的路径。
(4)16位 Windows 系统目录。没有函数可以获取该目录的路
径,但该目录会被搜索到,这个目录的名称是System。
(5)Windows目录。可以使用GetWindowsDirectory函数来得到该
目录的路径。
(6)PATH环境变量中列出的目录。
三、进程退出相关API
进程终止的方法:
- 主线程的进入主函数返回(最好使用这个方法),给句柄发送close消息自动撤销(推荐)
- 进程中的一个线程调用ExitProcess函数(尽量避免)
- 另外一个进程中的线程调用TerminateProcess函数(尽量避免)
- 进程中的所有线程自行终止运行(这种情况几乎从未发生)
PS:ExitPorcess 在执行后程序就直接退出终止,不会进行内存的释放等。
ExitProcess
注意:
- 酌情使用,只能结束自己;
- 调用时即结束,注意调用前清理资源
- dll会被调入dllmain,并传入DLL_PROCESS_DETTACH标志
VOID WINAPI ExitProcess(
_In_ UINT uExitCode
);
参数:传入一个退出码,直接退出进程 不会管后面资源释放等问题
void CProcessDlg::OnBnClickedButton4()
{
ExitProcess(0);
int n =100;
}
TerminateProcess
BOOL WINAPI TerminateProcess(
_In_ HANDLE hProcess,
_In_ UINT uExitCode
);
g_pi 是CreateProcess的最后一个参数;
GetCurrentProcess
获取自己进程句柄的函数
GetExitCodeProcess
BOOL GetExitCodeProcess(
HANDLE hProcess, // 进程句柄
LPDWORD lpExitCode // 终止状态,结束返回码
);
应用场景:守护进程,判断进程是否正常退出,如果不是就继续给他重启软件。
宏:STILL_ACTIVE,当进程未终止,返回的是这个宏0x103,终止返回退出码
注意:如果上面两个API后面还有代码,上面两种方式是不会执行后面代码的
正常情况下是:构造析构都可以,但是结束进程了,没有析构;局部变量没有释放资源的地方;影响不是很大。所以我们在调用退出的API要注意释放资源,清理资源,先做完去退出;
TerminateProcess更不推荐,它结束其他进程,其他进程更没有机会清理资源;压根不知道进程是什么时候被结束的;
当我们创建一个进程,进程会得到一个4g的虚拟内存,exe的代码、dll都会映射到进程;当进程退出的时候,映射关系都会取消,4g内存也会被销毁(里面的东西)——4g内存申请的堆,栈,就也都没了;进程打开的句柄也全部被关闭;
问:既然进程退掉 4g的虚拟内存映射取消,那我申请的堆是不是就可以不管,让系统释放,可不可以这样?
答:千万不能这么做,进程不是一下就映射4g虚拟内存(all in),而是进程打开是用多少内存,映射多少内存,这个时候,凡是你申请的内存都会占用物理内存(不够交换到磁盘),此时如果不自己释放,物理内存会不断减少,不够就会交换到磁盘,频繁的操作磁盘会影响内存的读写速度,交换速度越来越慢,卡!所以在内存管理的时候一定要释放!不要依赖进程退出的时候给你释放!
四、如何理解虚拟内存空间
虚拟内存是一种计算机系统中的内存管理技术,它使用了一种抽象的、逻辑上连续的地址空间,称为虚拟内存空间。虚拟内存空间为每个进程提供了一个独立的地址空间,使得每个进程都认为自己拥有连续的可用内存。
虚拟内存的实现涉及到硬件和操作系统的支持,下面是对虚拟内存的理解:
-
虚拟地址空间:虚拟内存空间由连续的虚拟地址组成,每个进程都拥有独立的虚拟地址空间。虚拟地址是由操作系统分配给进程的,进程通过虚拟地址进行内存访问,而不需要直接操作物理内存地址。
-
分页和分段:虚拟内存将虚拟地址划分为固定大小的页或段。分页是虚拟内存管理的常见方式,将虚拟地址空间划分为固定大小的页面,对应于物理内存中的页面。分段是另一种方式,将虚拟地址空间划分为不同大小的段,每个段对应着一段连续的物理内存。
-
地址映射:操作系统通过地址映射将虚拟地址转换为物理地址。当进程访问虚拟内存时,操作系统根据页表或段表中的映射关系,将虚拟地址转换为对应的物理地址。这样,进程可以访问到自己独立的虚拟内存空间,而不会影响其他进程的内存。
-
内存管理单元(MMU):虚拟内存的实现离不开硬件中的内存管理单元(MMU)。MMU负责进行虚拟地址到物理地址的转换,并处理访问权限、缺页中断等相关操作。MMU通过使用页表或段表中的映射关系,将虚拟地址转换为物理地址。
-
虚拟内存管理:操作系统负责管理虚拟内存,包括分配虚拟地址空间、页面置换、页面调度等。操作系统通过页表或段表来跟踪虚拟内存的映射关系,并在需要时进行页面置换,将不常用的页面置换到磁盘中,以释放内存空间供其他进程使用。
虚拟内存的主要优势是可以将进程的虚拟内存空间映射到物理内存和磁盘上,从而扩大了进程的可用内存空间,并提供了更好的内存管理和保护机制。同时,虚拟内存也能够提供内存隔离,使得每个进程都拥有独立的内存空间,相互之间不会互相干扰。
五、关于UAC
UAC(用户账户控制)是一种安全功能,存在于Windows操作系统中。它的目的是提高系统安全性,防止未经授权的更改或恶意软件的安装。UAC通过限制标准用户在系统中的权限,要求他们在执行需要管理员权限的操作时进行确认或提供管理员凭据。
当一个标准用户尝试执行需要管理员权限的操作时,UAC会弹出一个提示框,要求用户确认或提供管理员凭据。如果用户确认或提供凭据,UAC会提升用户权限并允许操作执行。这种方式确保了只有经过授权的用户才能进行敏感操作,减少了恶意软件的影响范围。
如果这个项目需要管理员权限,可以这样设置