WINDOWS的内存管理【虚拟内存管理】(一) - 中国WEB开发者网络 (http://www.webasp.net) -- 技术教程 (http://www.webasp.net/article/) --- WINDOWS的内存管理【虚拟内存管理】(一) (http://www.webasp.net/article/29/28054.htm) |
| -- 作者:未知 -- 发布日期: 2006-12-22 |
基本概念【摘录】 当进程被创建并被赋予它的地址空间时,该可用地址空间的主体是空闲的,即未分配的。若要使用该地址空间的各个部分,必须通过调用VirtualAlloc函数来分配它里边的各个区域。对一个地址空间的区域进行分配的操作称为保留(reserving)。 在较老的操作系统中,物理存储器被视为计算机拥有的RAM的容量。换句话说,如果计算机拥有16MB的RAM,那么加载和运行的应用程序最多可以使用16MB的R A M。今天的操作系统能够使得磁盘空间看上去就像内存一样。磁盘上的文件通常称为页文件,它包含了可供所有进程使用的虚拟内存。 保护属性 几个API函数 如果VirtualAlloc函数能够满足你的要求,那么它就返回一个值,指明保留区域的基地址。如果传递一个特定的地址作为pvAddress参数,那么该返回值与传递给VirtualAlloc的值相同,并被圆整为(如果需要的话)64KB边界值。 在保留区域中的提交存储器 有时你可能想要在保留区域的同时,将物理存储器提交给它。只需要一次调用VirtualAlloc函数就能进行这样的操作,如下所示: 回收虚拟内存和释放地址空间区域 改变内存页面的保护属性 确定地址空间的状态 说明,上述介绍的函数都是针对本进程而言的,如果要操作其他进程的内存信息,可以使用*****Ex结构的函数,例如要查询其他进程的地址空间状态,可以使用VirtualQueryEx函数,用法几乎一样,就是多了一个要查询进程的句柄。 DELPHI中的内存分配
程序界面: 程序的演示使用: 例如,你首先通过【申请内存-保留】按钮保留一块区域,然后提交页面1,因为对页面1,我代码中设置的保护属性是PAGE_READONLY,所以在此时,你尝试进行写操作是会失败的。你可以通过【修改保护属性】按钮来将页面1的保护属性修改为PAGE_READWRITE,再尝试写操作,OK! 你还可以换一个方式来测试,将代码中的Data : array[0..4093] of Char;改为4099,总之,是大于一个页面,此时,你依然只对页面1进行内存提交,并赋值可以读写的属性,你会发现,当你尝试进行写入操作时,依然会失败,原因很简单,TTestMemAlloc结构的大小已经大于一个页面,而第二个页面,我们并没有提交。 程序源码:
![]() ...{ 作者:wudi_1982 联系方式:wudi_1982@hotmail.com 本程序用来演示windows虚拟内存的操作 转载请著名出处 }![]() unit AllowMemun;![]() interface![]() uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, ExtCtrls, Buttons;![]() //常量定义,用来表示程序要一共要分配多少个页面 const MAXUSEPAGE=20;![]() type // 用来尝试对分配的内存进行写操作的结构 TTestMemAlloc=record Data : array[0..4093] of Char; end; TfrmAllowMem = class(TForm) GroupBox1: TGroupBox; Image1: TImage; Image2: TImage; btnPost1: TButton; Button5: TButton; btnPost45: TButton; btnPostLast: TButton; GroupBox2: TGroupBox; btnReserve: TButton; btnFree: TButton; lbpgSize: TLabel; Label1: TLabel; edOffSize: TEdit; edSize: TEdit; cmbxP: TComboBox; btnPost: TButton; btnDeCom: TButton; btChangeP: TButton; lsbxInfo: TListBox; panel1: TPanel; btnShow: TButton; edCount: TEdit; Label2: TLabel; Button1: TButton; procedure btnReserveClick(Sender: TObject); procedure btnFreeClick(Sender: TObject); procedure btnPost1Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure btnPost45Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure btnPostLastClick(Sender: TObject); procedure btnPostClick(Sender: TObject); procedure btnDeComClick(Sender: TObject); procedure btChangePClick(Sender: TObject); procedure btnShowClick(Sender: TObject); procedure Button1Click(Sender: TObject); private Arrayptr : Pointer; PageSize : integer; function GetPageSize:DWORD; procedure showMemBackupMap; procedure ShowMemMap(StartAddress : Pointer;ShowPageCount : integer); public![]() ...{ Public declarations } end;![]() var frmAllowMem: TfrmAllowMem;![]() implementation![]() uses RTLConsts, Types;![]() ![]() ...{$R *.dfm}![]() ![]() function DisplayProtections(ProtectFlag: DWORD):string; begin case ProtectFlag of PAGE_READONLY: result:='PAGE_READONLY'; PAGE_READWRITE: result:='PAGE_READWRITE'; PAGE_WRITECOPY: result:='PAGE_WRITECOPY'; PAGE_EXECUTE: result:='PAGE_EXECUTE'; PAGE_EXECUTE_READ: result:='PAGE_EXECUTE_READ'; PAGE_EXECUTE_READWRITE: result:='PAGE_EXECUTE_READWRITE'; PAGE_EXECUTE_WRITECOPY: result:='PAGE_EXECUTE_WRITECOPY'; PAGE_GUARD: result:='PAGE_GAURD'; PAGE_NOACCESS: result:='PAGE_NOACCESS'; PAGE_NOCACHE: result:='PAGE_NOCACHE'; end; end;![]() function TfrmAllowMem.GetPageSize:DWORD ; var si : SYSTEM_INFO; begin GetSystemInfo(si); Result := SI.dwPageSize; end;![]() procedure TfrmAllowMem.btnReserveClick(Sender: TObject); begin Arrayptr := VirtualAlloc(NIL,PageSize * MAXUSEPAGE, MEM_RESERVE, PAGE_READWRITE); if Arrayptr = nil then begin ShowMessage('分配内存失败'); Exit; end; ShowMemMap(Arrayptr,MAXUSEPAGE); end;![]() ![]() ![]() procedure TfrmAllowMem.Button5Click(Sender: TObject); begin VirtualFree(Arrayptr,PageSize,MEM_DECOMMIT); ShowMemMap(Arrayptr,MAXUSEPAGE); end;![]() procedure TfrmAllowMem.btnFreeClick(Sender: TObject); begin VirtualFree(Arrayptr, 0, MEM_RELEASE) ; ShowMemMap(Arrayptr,MAXUSEPAGE); end;![]() procedure TfrmAllowMem.btnPost1Click(Sender: TObject); var p : Pointer; begin p := VirtualAlloc(Arrayptr,PageSize,MEM_COMMIT, PAGE_READONLY); if p= nil then showmessage('分配失败'); ShowMemMap(Arrayptr,MAXUSEPAGE); end;![]() ![]() procedure TfrmAllowMem.btnPost45Click(Sender: TObject); var p : Pointer; begin p := VirtualAlloc(pointer(longint(Arrayptr)+PageSize*3),PageSize*2,MEM_COMMIT,PAGE_READWRITE); if p = nil then ShowMessage('分配失败'); ShowMemMap(Arrayptr,MAXUSEPAGE); end;![]() procedure TfrmAllowMem.btnPostLastClick(Sender: TObject); var p : Pointer; begin p := VirtualAlloc(pointer(longint(Arrayptr)+PageSize*(MAXUSEPAGE-1)),PageSize,MEM_COMMIT,PAGE_READONLY); if p = nil then ShowMessage('分配失败'); ShowMemMap(Arrayptr,MAXUSEPAGE); end;![]() procedure TfrmAllowMem.FormCreate(Sender: TObject); begin lbpgSize.Caption := IntToStr(GetPageSize)+'Byte'; PageSize := GetPageSize; showMemBackupMap; end;![]() ![]() ![]() procedure TfrmAllowMem.btnPostClick(Sender: TObject); var p : Pointer; PageP : DWORD; begin PageP := PAGE_READONLY; case cmbxP.ItemIndex of 0 : PageP := PAGE_NOACCESS; 1 : PageP := PAGE_READONLY; 2 : PageP := PAGE_READWRITE; end; p := VirtualAlloc(pointer(longint(Arrayptr)+StrToInt(edOffSize.Text)), StrToInt(edSize.Text), MEM_COMMIT, PageP); if p= nil then showmessage('分配失败') else ShowMemMap(Arrayptr,MAXUSEPAGE);![]() ![]() end;![]() procedure TfrmAllowMem.btnDeComClick(Sender: TObject); begin VirtualFree(pointer(longint(Arrayptr)+StrToInt(edOffSize.Text)) , StrToInt(edSize.Text), MEM_DECOMMIT); ShowMemMap(Arrayptr,MAXUSEPAGE); end;![]() procedure TfrmAllowMem.btChangePClick(Sender: TObject); var PageP : DWORD; OldProt : integer; begin PageP := PAGE_READONLY; case cmbxP.ItemIndex of 0 : PageP := PAGE_NOACCESS; 1 : PageP := PAGE_READONLY; 2 : PageP := PAGE_READWRITE; end; if not VirtualProtect(pointer(longint(Arrayptr)+StrToInt(edOffSize.Text)) , StrToInt(edSize.Text), PageP, @OldProt) then ShowMessage('修改保护属性出错!') else ShowMemMap(Arrayptr,MAXUSEPAGE); end;![]() procedure TfrmAllowMem.showMemBackupMap; var wd,i,bwd : integer; begin Image2.Picture := nil; wd := Image2.Width div MAXUSEPAGE; bwd := wd div 2; Image2.Canvas.Brush.Color := clWhite; Image2.Canvas.FillRect(Image2.ClientRect); for i := 1 to MAXUSEPAGE-1 do begin Image2.Canvas.MoveTo(wd*i,0); Image2.Canvas.LineTo(wd*i,Image2.Height); Image2.Canvas.TextOut((i-1)*wd+bwd,Image2.Height div 2,IntToStr(i)); end;![]() end;![]() procedure TfrmAllowMem.ShowMemMap(StartAddress : Pointer;ShowPageCount : integer); var MemInfo: TMemoryBasicInformation; PageCount,UseCount,wd : integer; cl : TColor; Addr : Pointer; begin Addr := StartAddress; UseCount := 0; Image1.Picture := nil; Image1.Canvas.Rectangle(Image1.ClientRect) ; lsbxInfo.Clear; wd := Image1.Width div ShowPageCount; while Longint(Addr) < Longint(Arrayptr)+ShowPageCount*PageSize do begin VirtualQuery(addr, MemInfo, SizeOf(TMemoryBasicInformation)); with lsbxInfo do begin Items.Add('-----------------------------'); Items.Add('基地址: '+IntToHex(Longint(MemInfo.BaseAddress),8)); Items.Add('分配地址: '+IntToHex(Longint(MemInfo.AllocationBase),8)); Items.Add('区域大小: '+IntToStr(MemInfo.RegionSize)+' bytes'+'['+ IntToHex(MemInfo.RegionSize,8 )+']'); PageCount := MemInfo.RegionSize div PageSize;![]() Items.Add('所分配保护属性: '+DisplayProtections(MemInfo.AllocationProtect)); Items.Add('访问的保护属性: '+DisplayProtections(MemInfo.Protect)); cl := clWhite; case MemInfo.State of MEM_COMMIT: begin cl := clRed; Items.Add('内存状态: MEM_COMMIT');![]() end; MEM_FREE: begin Items.Add('内存状态: MEM_FREE'); cl := clYellow; end; MEM_RESERVE: begin Items.Add('内存状态: MEM_RESERVE'); cl := clGreen; end; end; case MemInfo.Type_9 of MEM_IMAGE: Items.Add('内存类型: MEM_IMAGE'); MEM_MAPPED: Items.Add('内存类型: MEM_MAPPED'); MEM_PRIVATE: Items.Add('内存类型: MEM_PRIVATE'); end; end;![]() Image1.Canvas.Rectangle(Rect( UseCount*wd, 0, (UseCount+PageCount)*wd, Image1.Height)); Image1.Canvas.Brush.Color := cl;![]() Image1.Canvas.FillRect(Rect( UseCount*wd, 0, (UseCount+PageCount)*wd, Image1.Height)); UseCount := UseCount + PageCount;![]() Addr := Pointer(Longint(MemInfo.BaseAddress)+MemInfo.RegionSize); end; end;![]() procedure TfrmAllowMem.btnShowClick(Sender: TObject); begin Image2.Picture := nil; showMemBackupMap; ShowMemMap(nil,StrToInt(edCount.Text)); end;![]() procedure TfrmAllowMem.Button1Click(Sender: TObject); var arrayTemp : ^TTestMemAlloc; begin arrayTemp := Arrayptr; arrayTemp^.Data := 'wuiasdfasdfasdfasdfasf'; showmessage(pchar(Arrayptr)); //pinteger(Arrayptr)^ := 12; end;![]() end.
窗体文件代码:
object frmAllowMem: TfrmAllowMem Left = 192 Top = 110 BorderStyle = bsSingle Caption = 'frmAllowMem' ClientHeight = 450 ClientWidth = 709 Color = clBtnFace Font.Charset = ANSI_CHARSET Font.Color = clWindowText Font.Height = -13 Font.Name = '宋体' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object GroupBox1: TGroupBox Left = 0 Top = 393 Width = 709 Height = 57 Align = alBottom Caption = '图形显示' TabOrder = 0 object Image1: TImage Left = 2 Top = 15 Width = 705 Height = 40 Align = alClient end object Image2: TImage Left = 2 Top = 15 Width = 705 Height = 40 Align = alClient Transparent = True end end object TPanel Left = 0 Top = 0 Width = 709 Height = 393 Align = alClient TabOrder = 1 object panel1: TPanel Left = 1 Top = 1 Width = 440 Height = 391 Align = alLeft Caption = 'panel1' TabOrder = 0 object TGroupBox Left = 1 Top = 57 Width = 438 Height = 72 Align = alTop Caption = '固定页面的提交/撤销' TabOrder = 0 object btnPost1: TButton Left = 8 Top = 23 Width = 57 Height = 25 Caption = '1页面' TabOrder = 0 OnClick = btnPost1Click end object Button5: TButton Left = 80 Top = 23 Width = 65 Height = 25 Caption = '撤销1' TabOrder = 1 OnClick = Button5Click end object btnPost45: TButton Left = 157 Top = 24 Width = 68 Height = 25 Caption = '4、5页面' TabOrder = 2 OnClick = btnPost45Click end object btnPostLast: TButton Left = 248 Top = 23 Width = 113 Height = 25 Caption = '提交最后一个页面' TabOrder = 3 OnClick = btnPostLastClick end end object GroupBox2: TGroupBox Left = 1 Top = 1 Width = 438 Height = 56 Align = alTop Caption = '保留/撤销一个区域' TabOrder = 1 object btnReserve: TButton Left = 16 Top = 23 Width = 113 Height = 25 Caption = '申请内存-保留' TabOrder = 0 OnClick = btnReserveClick end object btnFree: TButton Left = 150 Top = 23 Width = 75 Height = 25 Caption = '撤销' TabOrder = 1 OnClick = btnFreeClick end end object TGroupBox Left = 1 Top = 129 Width = 438 Height = 261 Align = alClient Caption = '高级' TabOrder = 2 object TLabel Left = 8 Top = 24 Width = 104 Height = 13 Caption = '制定起始地址偏移' end object TLabel Left = 254 Top = 21 Width = 28 Height = 13 Caption = 'Byte' end object TLabel Left = 10 Top = 52 Width = 78 Height = 13 Caption = '制定分配大小' end object TLabel Left = 255 Top = 51 Width = 28 Height = 13 Caption = 'Byte' end object TLabel Left = 12 Top = 78 Width = 52 Height = 13 Caption = '保护属性' end object lbpgSize: TLabel Left = 73 Top = 232 Width = 56 Height = 13 Caption = 'lbpgSize' end object Label1: TLabel Left = 8 Top = 232 Width = 52 Height = 13 Caption = '页面大小' end object Label2: TLabel Left = 8 Top = 168 Width = 296 Height = 13 Caption = '从进程虚拟内存开始地址显示 个页面的信息' end object edOffSize: TEdit Left = 125 Top = 19 Width = 121 Height = 21 TabOrder = 0 end object edSize: TEdit Left = 125 Top = 48 Width = |