Windows内存与进程管理器底层分析

Windows内存与进程管理器底层分析

内存与进程管理器

关于Windows NT内存管理器的高层次信息已经够多的了,所以这里不会再讲什么FLAT模型、虚拟内存之类的东西。这里我们只讲具体的底层的东西。我假定大家都了解>i386的体系结构。

目录

==========

00.内核进程线程结构体

01.页表

02.Hyper Space

03.System PTE'S

04.Frame data base (MmPfnDatabase)

05.Working Set

06.向pagefile换页

07.page fault的处理

08.从内存管理器角度看进程的创建

09.上下文切换

0a.某些未公开的内存管理器函数

0b.结语

附录

0c.某些未公开的系统调用

0d.附注及代码分析草稿

00.内核进程线程结构体

===================================

Windows NT中的每一个进程都是EPROCESS结构体。此结构体中除了进程的属性之外还引用了其它一些与实现进程紧密相关的结构体。例如,每个进程都有一个或几个线程,线程在系统中就是ETHREAD结构体。我来简要描述一下存在于这个结构体中的主要的信息,这些信息都是由对内核函数的研究而得知的。首先,结构体中有KPROCESS结构体,这个结构体中又有指向这些进程的内核线程(KTHREAD)链表的指针(分配地址空间),基优先级,在内核模式或是用户模式执行进程的线程的时间,处理器affinity(掩码,定义了哪个处理器能执行进程的线程),时间片值。在ETHREAD结构体中还存在着这样的信息:进程ID、父进程ID、进程映象名、section 指针。quota定义了所能使用的分页和非分页池的极限值。VAD(virtual address descriptors)树定义了用户地址空间内存区的状况。关于Working Set的信息定义了在给定时间内有那些物理页是属于进程的。同时还有limit与statistics。ACCESS TOKEN描述了当前进程的安全属性。句柄表描述了进程打开的对象的句柄。该表允许不在每一次访问对象时检查访问权限。在EPROCESS结构体中还有指向PEB的指针。

ETHREAD结构体还包含有创建时间和退出时间、进程ID和指向EPROCESS的指针,启动地址,

I/O请求链表和KTHREAD结构体。在KTHREAD中包含有以下信息:内核模式和用户模式线程的创建时间,指向内核堆栈基址和顶点的指针、指向服务表的指针、基优先级与当前优先级、指向APC的指针和指向TEB的指针。KTHREAD中包含有许多其它的数据,通过观察这些数据可以分析出KTHREAD的结构。

01.页表

==================

通常操作系统使用页表来进行内存操作。在Windows NT中,每一个进程都有自己私有的页表(进程的所有线程共享此页表)。相应的,在进程切换时会发生页表的切换。为了加快对页表的访问,硬件中有一个translation lookaside buffer(TLB)。在Windows NT中实现了两级的转换机制。在386+处理器上将虚拟地址转换为物理地址过程(不考虑分段)如下:

Virtual Address

+-------------------+-------------------+-----------------------+

|3 3 2 2 2 2 2 2 2 2|2 2 1 1 1 1 1 1 1 1|1 1 |

|1 0 9 8 7 6 5 4 3 2|1 0 9 8 7 6 5 4 3 2|1 0 9 8 7 6 5 4 3 2 1 0|

+-------------------+-------------------+-----------------------+

| Directory index | Page Table index | Offset in page |

+-+-----------------+----+--------------+-----+-----------------+

| | |

| | |

| Page Directory (4Kb)| Page Table (4Kb) | Frame(4Kb)

| +-------------+ | +-------------+ | +-------------+

| | 0 | | | 0 | | | |

| +-------------+ | +-------------+ | | |

| | 1 | | | 1 | | | |

| +-------------+ | +-------------+ | | |

| | | +->| PTE +-+ | | |

| +-------------+ +-------------+ | | | ----------- |

+->| PDE +-+ | | | +->| byte |

+-------------+ | +-------------+ | | ----------- |

| | | | | | | |

+-------------+ | +-------------+ | | |

| | | | | | | |

... | ... | | |

| 1023 | | | 1023 | | | |

CR3->+-------------+ +----->+-------------+ +--->+-------------+

Windows NT 4.0使用平面寻址。NT的地址空间为4G。这4G地址空间中,低2G(地址0-0x7fffffff)属于当前用户进程,而高2G(0x80000000-0xffffffff)属于内核。在上下文切换时,要更新CR3寄存器的值,结果就更换了用户地址空间,这样就达到了进程间相互隔绝的效果。

注:在Windows NT中,从第4版起,除4Kb的页之外同时还使用了4Mb的页(Pentium及更高)来映射内核代码。但是在Windows NT中没有实际对可变长的页提供支持。

PTE和PDE的格式实际上是一样的。

PTE

+---------------+---------------+---------------+---------------+

|3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | |

|1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0|

+---------------------------------------+-----------------------+

| |T P C U R D A P P U R P|

| Base address 20 bits |R P W C W S W |

| |N T D T |

+---------------------------------------+-----------------------+

一些重要的位在i386+下的定义如下:

---------------------------------------------------------------------------

P - 存在位。此位如果未设置,则在地址转换时会产生异常。一般说来,在一些情况下NT内核会使用未设置此位的PTE。

例如,如果向pagefile换出页,保留这些位可以说明其在页面文件中的位置和pagefile号。U/S - 是否能从user模式访问页。正是借助于此位提供了对内核空间的保护(通常为高2G)。RW - 是否能写入

NT使用的为OS设计者分配的空闲位

---------------------------------------------------------------------------

PPT - proto pte

TRN - transition pte

当P位未设置时,第5到第9位即派上用场(用于page fault处理)。它们叫做Protection Mask,样子如下:

--------------------------------------------------------------------------------------

* MiCreatePagingFileMap

9 8 7 6 5

---------

| | | | |

| | | | +- Write Copy

| | | +--- Execute

| | +----- Write

| +------- NO CACHE

+--------- Guard

GUARD | NOCACHE组合就是NO ACCESS

* MmGetPhysicalAddress

函数很短,但能从中获得很多信息。在虚地址0xc0000000 - 0xc03fffff上映射有进程的页表。并且,映射的机制非常精巧。在Directory Table(以下称DT)有1100000000b个表项(对应于地址0xc000..-0xc03ff..)指向自己,也就是说对于这些地址DT用作了页表(Page Table)!如果我们使用,比如说,地址(为方便起见使用二进制)

1100000000.0000000101.0000001001.00b

---------- ---------- --------------

0xc0... 页表选择页表内偏移

页目录

通过页表101b的1001b号,我们得到了PTE。但这还没完——DT本身映射在地址

0xc0300000-0xc0300ffc上。在MmSystemPteBase中有值0xc0300000。为什么这样——看个例子就知道了:

1100000000.1100000000.0000001001.00b

---------- ---------- --------------

0xc0... 0xc0... 页目录偏移

页目录页表-

页目录

选择

最后,在c0300c00包含着用于目录本身的PDE。这个PDE的基地址的值保存在MmSystemPageDirectory中。同时系统为映射物理页MmSystemPageDirectory保留了一个PTE,这就是MmSystemPagePtes。

这样做能简化寻址操作。例如,如果有PTE的地址,则PTE描述的页的地址就等于PTE<<10。反过来:PTE=(Addr>>10)+0xc0000000。

除此之外,在内核中存在着全局变量MmKseg2Frame = 0x20000。该变量指示在从0x80000000开始的哪个地址区域直接映射到了物理内存,也就是说,此时虚拟地址0x80000000 - 0x9fffffff 映射到了物理地址00000000-1f000000。

还有几个有意思的地方。从c0000000开始有个0x1000*0x200=0x200000=2M的描述地址的表(0-7fffffff)。描述这些页的PDE位于地址c0300000-0xc03007fc。对于i486,在地址

c0200000-c027fffc应该是描述80000000到a0000000的512MB的表,但对于Pentium在区域0xc0300800-0xc03009fc是4MB的PDE,其描述了从0 到1fc00000的步长为00400000的4M 的物理页,也就是说选择了4M的页。对应于这些PDE的虚地址为80000000, 9fffffff。

这样我们就得到了页表的分布:

范围c0000000 - c01ffffc 用于00000000-7fffffff的页表

范围c0200000 - c027ffff "吃掉" 4M地址页的地址

范围c0280000 - c02ffffc 包含用于a0000000 - bfffffff的页

范围c0300000 - c0300ffc PD 本身(描述范围c0000000 - c03fffff)

范围c0301000 - c03013fc c0400000 - c04fffff HyperSpace (更准确的说, 是1/4的hyper space)

范围c0301400 - c03fffff 包含用于c050000 - ffffffff的页

注:在0xc0301000-0xc0301ffc包含有描述hyper space的页表。这是内核的地址空间,且对于不同的进程映射的内容是不同的(另一方面,内核空间又总是在每个用户进程的上下文中)。这是进程私有的区域。例如,working set就位于hyper space中。页表的前256个PTE(hyper space 的前1/4)为内核保留,而且在需要快速向frame中映射虚拟地址时使用。

我给出一个向区域0xc0200000-0xc027f000中一个地址进行映射的例子。

1100000000.1000000000.000000000000 = 0xc0200000

1) 解析出PDE #1100000000 (4k 页) 并选出PageDirectory

2) 在Directory 中选出PTE #1000000000 (c0300800)

这是个4MB 的PDE - 但这里忽略位长度,

因为PDE 用作了PTE. 结果c0200000 - c0200fff 被映射为

80000000-80000fff

c0201000 映射到下面的- 80400000- 80400fff.

等等直到c027f000 - 9fc00000

PTE, 位于c0200000到c027fffc - 描述了80000000 - 9ffffc00 (512m)

02.Hyper Space

==============

HyperSpace是内核空间中的一块区域(4mb), 不同的进程映射内容不同。对于转换,4MB足够放下页表完整的一页。这个表位于地址0xc0301000 - 0xc0301ffc(PDE的第0个表项位于

0xc0300c04)。在内部,为向HyperSpace区域中映射物理页(当需要快速为某个frame组织虚拟地址时)要使用函数:

DWORD MiMapPageInHyperSpace(DWORD BaseAddr,OUT PDWORD Irql);

它返回HyperSpace中的虚拟地址,这个虚拟地址被映射到所要的物理页上。这个函数是如何工作的,工作的时候用到了什么?

在内核中有这样的变量:

MmFirstReservedMappingPte=0xc0301000

MmLastReservedMappingPte=0xc03013fc

这两个变量描述了255个pte,这些pte描述了区域:

0xc0400000-0xc04fffff (1/4 HyperSpace)

在MmFirstReservedMappingPte处是一个pte,其中的基址扮演了计数器的角色(从0到255)(当然,pte是无效的,p位无效)。为所需地址添加pte时要依赖计数器当前的值……并且计数器使用了下开口堆栈的原理,从ff开始。一般来说,页表中的pte用作信息上的目的并不是唯一的情况。

03.System PTE'S

===============

在内核中有一块这样的内存——系统pte。什么是系统pte,以及内核如何使用系统pte?

*见函数MiReserveSystemPtes(...)

系统为空闲PTE维护了某些结构体。首先为了快速满足密集请求(当内核需要pte映射某些物理页时)系统中有个Sytem Ptes Pool。而且pool中有pte blocks(blocks表示请求是以block 为单位来满足的,一个block中有一些pte,1、2、4、8和16个pte)。

系统中有以下这些表:

BYTE MmSysPteTables[16]={0,0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4};

DWORD MmSysPteIndex[5]={1,2,4,8,16};

DWORD MmFreeSysPteListBySize[5];

PPTE MmLastSysPteListBySize[5];

DWORD MmSysPteListBySizeCount[5];

DWORD MmSysPteMinimumFree[5]={100,50,30,20,20}

PVOID MmSystemPteBase;// 0xc0200000

在pool中的空闲PTE被组织成了链表(当然,pte是位于页表中,也就是说链表结构体位于页表中,这是真的)。链表的元素:

typedef struct _FREE_SYSTEM_PTES_BLOCK{

/*pte0*/ SYSPTE_REF NextRef; // 指向后面的block

/*pte1*/ DWORD FlushUnkn; // 在Flush时使用

/*pte2*/ DWORD ArrayOfNulls[ANY_SIZE_ARRAY]; // 空闲PTE

}FREE_SYSTEM_PTES_BLOCK PFREE_SYSTEM_PTES_BLOCK;

用作指向后面元素指针的PTE的地址可如此获得:VA=(NextRef>>10)+MmSystemPteBase (低10位永远为0,相应的p位也为0)。链表最后一个元素NextRef域的值为0xfffff000 (-1) 。相

应的,链表有5个(block大小分别为1,2,4,8和16个pte)。

*见函数MiReserveSystemPtes2(...) / MiInitializeSystemPtes

除pool外还有一个undocumented的空闲系统pte链表。

PPTE MmSystemPtesStart[2];

PPTE MmSystemPtesEnd[2];

SYSPTE_REF MmFirstFreeSystemPte[2];

DWORD MmTotalFreeSystemPtes[2];

在两个链表中有两个引用。链表的元素:

typedef struct _FREE_SYSTEM_PTES{

SYSPTE_REF Next; // #define ONLY_ONE_PTE_FLAG 2, last = 0xfffff000

DWORD NumOfFreePtes;

}FREE_SYSTEM_PTES PFREE_SYSTEM_PTES;

而且,1号链表原则上没有组织。0号链表(MiReleaseSystemPtes)用于释放的pte。pte有可能进入System Ptes Pool。若在请求MiReserveSystemPtes(...)时pte的数目大于16,则同时pte 从0号链表分配。也就是说,0号链表与pool有关联,而1号则没有。

为了使工作的结果不与TLB相矛盾,系统要么使用重载cr3,要么使用命令invlpg。“高级”函数

MiFlushPteList(PTE_LIST* PteList, BOOLEAN bFlushCounter, DWORD PteValue);

进行以下工作:

初始化PTE并调用invlpg(汇编指令)。

typedef struct PTE_LIST{

DWORD Counter; // max equ 15

PVOID PtePointersInTable[15];

PVOID PteMappingAddresses[15];

};

如果Counter大于15,则调用KeFlushCurrentTb(只是重载CR3),并且如果设置了bFlushCounter,则向MmFlushCounter加0x1000。

04.Page Frame Number Data Base (MmPfnDatabase)

======================================

内核将有关物理页的信息保存在pfn数据库中(MmPfnDatabase)。本质上讲,这只是个0x18

字节长的结构体块。每一个结构体对应一个物理页(顺序排列,所以元素常被称为Pfn - page frame number)。结构体的数量对应于系统中4KB页的数量(或者说是内核可见的页的数量,需要的话可以在boot.ini中使用相应的选项来为NT内核做出这块“坏”页区)。通常,结构体形式如下:

typedef struct _PfnDatabaseEntry

{

union {

DWORD NextRef; // 0x0 如果frame在链表中,则这个就是frame的号

// 最后的一个为-1

DWORD Misc; // 同时另外一项信息, 依赖于上下文

// 见伪代码(通常TmpPfn->0...)

// 通常这里有*KTHREAD, *KPROCESS,

// *PAGESUPPORT_BLOCK...

};

PPTE PtePpte; // 0x4 指向pte 或ppte

union { // 0x8

DWORD PrevRef; // 前面的frame或(-1, 第一个)

DWORD ShareCounter; // Share 计数器

};

WORD Flags; // 0xc 见下面

WORD RefCounter; // 0xe 引用计数

DWORD Trans; // 0x10 ?? 见下面. 用于pagefile

DWORD ContFrame;//ContainingFrame; // 14

}PfnDatabaseEntry;

/*

Flags (名字取自windbg !pfn的结果)

掩码位名字值

----- ---- --- --------

0001 0 M Modifyied

0002 1 R Read In Progress

0004 2 W WriteInProgress

0008 3 P Shared

0070 [4:6] Color Color (In fact Always null for x86)

0080 7 X Parity Error

0700 [8:10] State 0- Zeroed

/List 1- Free

2- StandBy

3- Modified

4- ModifiedNoWrite

5- BadPage

6- Active

7- Trans

0800 11 E InPageError

Trans域的值用在frame的内容位于PageFile中的时候或是frame的内容位于与这个Page File PTE对应的其它映象文件中的时候。

我给出未设置P位的PTE的例子(这种PTE不由平台体系结构确定,而由OS确定)。

* 取自@MiReleasePageFileSpace (Trans)

Page File PTE

+---------------------------------------+-+-+---------+-------+-+

|3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1|1|1|0 0 0 0 0|0 0 0 0|0|

|1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2|1|0|9 8 7 6 5|4 3 2 1|0|

+---------------------------------------+-+-+---------+-------+-+

| offset |T|P|Protect. |page |0|

| |R|P|mask |file | |

| |N|T| |Num | |

+---------------------------------------+-+-+---------+-------+-+

Transition PTE

+---------------------------------------+-+-+---------+-------+-+

|3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1|1|1|0 0 0 0 0|0 0 0 0|0|

|1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2|1|0|9 8 7 6 5|4 3 2 1|0|

+---------------------------------------+-+-+---------+-------+-+

| PFN |T|P|Protect. |C W O W|0|

| |R|P|mask |D T | |

| |N|T| | | |

+---------------------------------------+-+-+---------+-------+-+

W - write

O - owner

WT - write throuth

CD - cache disable

可能所有这些现在还不很易懂,但是看完下面就能明白了。当然,这个结构体是未公开的。显然,结构体能够组织成链表。frame由以下结构体支持:

struct _MmPageLocationList{

PPfnListHeader ZeroedPageListhead; //&MmZeroedPageListhead

PPfnListHeader FreePageListHead; //&MmFreePageListHead

PPfnListHeader StandbyPageListHead; //&MmStandbyPageListHead

PPfnListHeader ModifiedPageListHead; //&MmModifiedPageListHead

PPfnListHeader ModifiedNoWritePageListHead;//&MmModifiedNoWritePageListHead

PPfnListHeader BadPageListHead; //&MmBadPageListHead

}MmPageLocationList;

这其中包含了6个链表。各域的名字很好的说明了它们的用处。frame的状态与这些链表密切关联。下面列举了frame的状态:

+---------------+----------------------------------------------------+------+

|状态|描述 | 链表|

+---------------+----------------------------------------------------+------+

|Zero |清零的可用空闲页 | 0 |

|Free |可用空闲页 | 1 |

|Standby |不可用但可轻易恢复的页 | 2 |

|Modified |要换出的dirty页| 3 |

|ModifiedNoWrite|不换出的dirty页| 4 |

|Bad |不可用的页(有错误) | 5 |

|Active |活动页,至少映射一个虚拟地址 | - |

+---------------+----------------------------------------------------+------+

frame可能处在6个链表中的某一个,也可能不在这些链表中(状态为Active)。如果页属于某个进程,则这个页就被记录在Working Set中(见后面)。同时,如果frame由内存管理器自己使用,则一般可以不考虑这些frame的位置。

每个链表的表头都是下面这个样子:

typedef struct _PfnListHeader{

DWORD Counter; // 链表中frame的数目

DWORD LogNum; // 链表号.0 - zeroed, 1- Free etc...

DWORD FirstFn; // MmPfnDatabase中的第一个frame号

DWORD LastFn; // --//--- 最后一个.

}PfnListHeader PPfnListHeader;

除此之外,可以用“color”(就是cache)来寻址空闲frame(zeroed或是free)。如果看一下附录中的伪代码就容易理解了。我给出两个结构体:

struct {

ColorHashItem* Zeroed; //(-1) нет

ColorHashItem* Free;

}MmFreePagesByColor;

typedef struct _ColorHashItem{

DWORD FrameNum;

PfnDatabaseEntry* Pfn;

} ColorHashItem;

有一套函数使用color来处理frame(处理cache)。例如,MiRemovePageByColor(FrameNum, Color); 看一下这些函数及其参数返回值的名称和函数的反汇编代码,很容易猜到相应的内容,所以这里就不描述了,在说一句,这些函数都是未导出的。在使用color的时候,要考虑color 掩码,最后选择color。

Windows NT符合C2安全等级,所以应该在为进程分配页的时候应将页清零。我们来看一下将frame清零的系统进程的线程。最后,在Phase1Initialization()中所作的是调用MmZeroPageThread。不难猜到——线程将空闲页清零并将其移动到zeroed页的链表中。

MmZeroPageThread

{

//

//.... 没意思的东西我们略过;)

//

while(1)

{

KeWaitForSingleObject(MmZeroingPageEvent,8,0,0,0); // 等待事件

while(!KeTryToAcquireSpinLock(MmPfnLock,&OldIrql)); // 获取PfnDatabase

while(MmFreePageListHead.Count){

MiRemoveAnyPage(MmFreePageListHead.FirstFn&MmSecondaryColorMask);

// 从空闲链表中取出页

Va=MiMapPageToZeroInHyperSpace(MmFreePageListHead.FirstFn);

KeLowerIrql(OldIrql);

memset(Va,0,0x1000); // clear page

while(!KeTryToAcquireSpinLock(MmPfnLock,&OldIrql);

MiInsertPageInList(&MmZeroedpageListHead,FrameNum);

// 将已清零的页插入Zero链表

}

MmZeroingPageThreadActive=0; // 清标志

KeLowerIrql(OldIrql);

}

// 永不退出

}

// 函数只是将frame映射到定义的地址上

// 以使其可被清零

DWORD MiMapPageToZeroInHyperSpace(FrameNum)

{

if(FrameNum

TmpPte=0xc0301404;

TmpVa=0xc0501000;

*TmpPte=0;

invlpg((void*)TmpVa); // asm instruction in fact

*TmpPte=FrameNum<<12|ValidPtePte;

return TmpVa; // always 0xc0501000;

}

在何时MmZeroingPageEvent被激活?这发生在向空闲页链表中添加frame的时候:

MiInsertPageInList()

{

.....

if(MmFreePageListHead.Count>=MmMinimumFreePagesToZero&&

!MmZeroingPageThreadActive)

{

MmZeroingPageThreadActive=1;

KeSetEvent(&MmZeroingPageEvent,0,0);

}

....

}

注:内核并不总是依赖这个线程,有时会遇到这样的代码,它获取一个空闲页,用过后自己将其清零。

05.Working Set

==============

Working Set——工作集,是属于当前进程的物理页集。内存管理器使用一定的机制跟踪进程的工作集。working set有两个限额:maximum working set和minimum working set。这是工作集的最大值和最小值。内存管理器以这两个值为依据来维护进程的工作集(工作集大小不小于最小值,不大于最大值)。在定义条件的时候,工作集被裁减,这时工作集的frame落入空闲链表。内核工作集是结构体的总和。

在进程结构体的偏移0xc8(NT4.0)有以下结构体。

typedef struct _VM{

/* C8*/ LARGE_INTEGER UpdateTime; //0

/* D0*/ DWORD Pages; //8 called so, by S-Ice authors

/* D4*/ DWORD PageFaultCount //0c faults;

// in fact number of MiLocateAndReserveWsle calls

/* D8*/ DWORD PeakWorkingSetSize; //10 all

/* DC*/ DWORD WorkingSetSize; //14 in

/* E0*/ DWORD MinimumWorkingSet; //18 pages, not in

/* E4*/ DWORD MaximumWorkingSet; //1c bytes

/* E8*/ PWS_LIST WorkingSetList; //20 data table

/* EC*/ LIST_ENTRY WorkingSetExpansion; //24 expansion

/* F4*/ BYTE fl0; // Operation??? //2c

BYTE fl1; // always 2??? //2d

BYTE fl2; // reserved??? always 0 //2e

BYTE fl3; // //2f

}VM *PVM;

WinDbg !procfields的扩展命令用到VM。这里重要的是,跟踪page fault的数量(PageFaultCount),MaximumWorkingSet和MinimumWorkingSet,管理器以它们为基础来支持工作集。

注:实际上,PageFaultCount并非是严格的计数。这个计数在MiLocateAndReserveWsle函数中被扩大,因为这个函数不只在page fault时被调用,在某些其它情况下也会被调用(真的,很少见)。

下面这个结构体描述了包含工作集页的表。

typedef struct _WS_LIST{

DWORD Quota; //0 ??? i'm not shure....

DWORD FirstFreeWsle; // 4 start of indexed list of free items

DWORD FirstDynamic; // 8 Num of working set wsle entries in the start

// FirstDynamic

DWORD LastWsleIndex; // c above - only empty items

DWORD NextSlot; // 10 in fact always == FirstDynamic

// NextSlot

PWSLE Wsle; // 14 pointer to table with Wsle

DWORD Reserved1 // 18 ???

DWORD NumOfWsleItems; // 1c Num of items in Wsle table

// (last initialized)

DWORD NumOfWsleInserted; // 20 of Wsle items inserted (WsleInsert/

// WsleRemove)

PWSHASH_ITEM HashPtr; // 24 pinter to hash, now we can get index of

// Wsle item by address. Present only if

// NumOfWsleItems>0x180

DWORD HashSize; // 28 hash size

DWORD Reserved2; // 2c ???

}WS_LIST *PWS_LIST;

typedef struct _WSLE{ // 工作集表的元素

DWORD PageAddress;

}WSLE *PWSLE;

// PageAddress 本身是工作集页的虚地址

// 低12位用作页属性(虚地址总是4K的倍数)

#define WSLE_DONOTPUTINHASH 0x400 // 不放在cache中

#define WSLE_PRESENT 0x1 // 非空元素

#define WSLE_INTERNALUSE 0x2 // 被内存管理器使用的frame

// 未设置WSLE_PRESENT的空闲WSLE本身是下一个空闲WSLE的索引。这样,空闲的WSLE 就组织成了链表。最后一个空闲WSLE表示为-1。

#define EMPTY_WSLE (next_emty_wsle_index) (next_emty_wsle_index<<4)

#define LAST_EMPTY_WSLE 0xfffffff0

typedef struct _WSHASH_ITEM{

DWORD PageAddress; //Value

DWORD WsleIndex; //index in Wsle table

}WSHASH_ITEM *PWSHASH_ITEM;

//cache函数很简单。内部函数的伪代码:

//MiLookupWsleHashIndex(Value,WorkingSetList)

//{

//Val=value&0xfffff000;

//TmpPtr=WorkingSetList->HashPtr;

//Mod=(Val>>0xa)%(WorkingSetList->HashSize-1);

//if(*(TmpPtr+Mod*8)==Val)return Mod;

//while(*(TmpPtr+Mod*8)!=Val)){

// Mod++;

// if(WorkingSetList->HashSize>Mod)continue;

// Mod=0;

// if(fl)KeBugCheckEx(0x1a,0x41884,Val,Value,WorkingSetList);

// fl=1;

// }

//return Mod;

//}

我们来看一下典型的进程working set。WorkingSetList位于地址MmWorkingSetList

(0xc0502000)。这是hyper space的区域,所以在进程切换时,要更新这些虚地址,这样,每个进程都有自己的工作集结构体。在地址MmWsle (0xc0502690)上是Wsle动态表的起始地址。表的结尾的地址总是0x1000的倍数,也就是说表可以结束在地址0xc0503000、0xc0504000等等上(这是为了简化对Wsle表大小的操作)。Cache(如果有)位于一个偏移上,Wsle不会向这个偏移增长。我们来详细看一下这个表:

// WsList-0xc0502000---

// ....

// -------0xc0502030----

// pde 00 fault counter

// pde 01 fault counter

// pde 02 fault counter

//

// +-Wsle==0xc0502690--- +--Pde/pte +-----Pfn[0]------

// |0 c0300000|403 Page Directory |c0300c00 pde |pProcess

// |4 c0301000|403 Hyper Space |c0300c04 pte |1

// |8 MmWorkingSetList(c0502000)|403 |c0301408 pte |2

// |c MmWorkingSetList+0x1000 | 403 |. |3

// |10 MmWorkingSetList+0x2000 | 403 |. .

// | ....

// |FirstDynamic*4 FrameN

// |.... |. .

// .

// |LastWsleIndex*4 FrameM

// +-------- +------ +-------

// | free items

// ....

// | 0xfffffff0

// +-------------------

// Cache

// ....

这里有个有意思的地方,在表的起始部分有FirstDynamic的页,用于建立Wsle,WorkingSetList 和cache。同时这里还有页目录frame,HyperSpace和某些其它的页,这些页是内存管理器所需要的,不能从工作集中移出(标志WSLE_INTERNALUSE)。之后,我们还能看到两种对Pfn frame 域偏移0使用的变体。对于页目录frame,这是指向进程的指针,对于通常的属于工作集的页,这是在表内的索引。

在WorkingSetList和Wsle表的起始地址之间还有不大的0x660字节的空闲空间。关于如何分配这些空间的信息是没有的,但是很快在WorkingSetList开始有用于用户空间(通常为低2GB)的page fault counter,也就是说如果,譬如说,索引0x100的元素有值3,则表示从3开始(如果不考虑可能的溢出)page fault用于范围[0x40000000-0x403fffff]的页。

工作集的限额在内核模式下可以通过导出的未公开函数来修改:

NTOSKRNL MmAdjustWorkingSetSize(

DWORD MinimumWorkingSet OPTIONAL, // if both == -1

DWORD MaximumWorkingSet OPTIONAL, // empty working set

PVM Vm OPTIONAL);

为处理WorkingSet,管理器使用了许多内部函数,了解了这些函数就能明白其工作的原理。

06.向pagefile换页

========================================

frame可以是空闲的——当RefCounter等于0且位于一个链表中时。frame可以属于工作集。在缺少空闲frame时或是在达到treshhold时,就会发生frame的换出。这方面的高层次函数是有的。这里的任务是用伪代码来证实。

在NT中有最多16个pagefile。pagefile的创建发生于模块SMSS.EXE。这时打开文件及其句柄向PsInitialSystemProcess进程的句柄表拷贝。我给出创建pagefile的未公开系统函数的原型(如果不从核心调用的话就必须有创建这种文件的权限)。

NTSTATUS NTAPI NtCreatePagingFile(

PUNICODE_STRING FileName,

PLARGE_INTEGER MinLen, // 高位双字应为0

PLARGE_INTEGER MaxLen, // minlen应大于1M

DWORD Reserved // 忽略

);

每个pagefile都有一个PAGING_FILE结构体。

typedef struct _PAGING_FILE{

DWORD MinPagesNumber; //0

DWORD MaxPagesNumber; //4

DWORD MaxPagesForFlushing; //8 (换出页的最大值)

DWORD FreePages; //c(Free pages in PageFile)

DWORD UsedPages; //10 忙着的页

DWORD MaxUsedPages; //14

DWORD CurFlushingPosition; //18 -???

DWORD Reserved1; //1c

PPAGEFILE_MDL Mdl1; // 20 0x61 - empty ???

PPAGEFILE_MDL Mdl2; // 24 0x61 - empty ???

PRTL_BITMAP PagefileMap; // 28 0 - 空闲, 1 - 包含换出页

PFILE_OBJECT FileObject; //2c

DWORD NumberOfPageFile; //30

UNICODE_STRING FileName; //34

DWORD Lock; //3d

}PAGING_FILE *PPAGING_FILE;

DWORD MmNumberOfActiveMdlEntries;

DWORD MmNumberOfPagingFiles;

#define MAX_NUM_OF_PAGE_FILES 16

PPAGING_FILE MmPagingFile[MAX_NUM_OF_PAGE_FILES];

在内存子系统启动时(MmInitSystem(...))会启动线程MiModifiedPageWriter,该线程进行以下工作:初始化MiPaging和MiMappedFileHeader,在非换出域中创建并初始化MmMappedFileMdl,建立优先级LOW_REALTIME_PRIORITY+1,等待KEVENT,初始化MmMappedPageWriterEvent和MmMappedPageWriterList链表,启动MiMappedPageWriter线程,启动函数MiModifiedPageWriterWorker。

在任务MiModifiedPageWriterWorker中会等待事件MmModifiedPageWriterEvent,处理链表MmModifiedNoWritePageList和MmModifiedPageList并准备实现向映象文件或pagefile的页换出(调用MiGatherMappedPages或是MiGatherPagefilePages)。

在MiGatherPagefilePages中使用IoAsynchronousPageWrite( )函数进行frame的换出。而且不是一个frame,而是一簇(页数目总和为MmModifiedWriteClasterSize)。向pagefile换出页是由PAGING_FILE结构体中的PagefileMap来跟踪的。

研究函数的伪代码在appendix.txt中。这里描述伪代码没有什么意义——都很简单。

07.page fault的处理

==============================

对于转向对pagefault的研究,我们现在有了所有必须的信息了。转换线性地址时,当线性地址(分页机制打开)的所用的PDE/PTE的P(present)位无效或是违反了保护规则,在+i386处理器里会产生异常14。这时,在堆栈中有错误代号,包含有以下信息:用户/内核错误位(异常发生在ring3还是ring0?),读写错误位(试图读还是写?),页存在位。除此之外,在CR2寄存器中存有产生异常的32位线性地址。内核中处理14号中断的是_KiTrap0E。

当要转换的页没有相应的物理页时,内存管理器执行确定好的工作来“修正”。这些是由异常处理函数调用高层函数MmAccessFault (Wr,Addr,P);来完成的。在对伪代码的进行分析之前,想一下在什么样的情况下会发生page fault是很有用的。

最显然的就是访问错误,这时ring3的代码试图写入PTE/PDE中未设置U位的页或是写入了只读的页(PTE/PDE中未设置W位)。再有,页可以被换出到页面文件中,对应于这些页的PTE 中未设置P位,但有信息指示在哪个页面文件中寻找frame,以及frame的偏移。还有一个类似的情况——frame属于映象文件。除此之外,所转换的页可能只属于已分配的内存区(使用NtAllocateMemory),也可能转换的是原先没转换过的页,这中情况下,VMM分配清零过的frame (这是C2的要求)。最后,异常还可能是由写copy on write页和转换共享内存引发。以上只列出了主要的情况。

处理的结果通常是向当前进程的Working Set中添加相应的frame。

异常的每一种情况都相应有一个内部的结构体与之相关联,VMM就处理这些结构体。这些结构体十分复杂,要对它们进行完整的描述的话,需要反汇编大量的函数。目前还没有大部分结构体的完整信息,但对于理解异常处理程序来说并不要求知道这些。我来大致描述一下VAD和PPTE 的概念,研究异常处理程序的伪代码要用到。

VAD

操作虚拟地址需要用到VAD (Virtual Address Descriptor)。我们熟知的(有一个几乎与之同名的Win32函数调用这个函数)未公开函数NtAllocateVirtualMemory(ring0下是ZwAllocateVirtualMemory)操作这些结构体。

每一个VAD都描述了虚地址空间中的区域,实际上,除了区域的起止地址外还有保护信息(见ZwAllocateVirualMemory函数的参数)。而同时还有其它一些特殊的信息(目前除了首部之外还没有VAD的完整信息)。VAD结构体只对用户地址(低2GB)有意义,使用这些结构体VMM 可以捕获到发生异常的区域。VAD的结构是一个平衡二叉树(有内部函数负责修整此树),这是为查找而进行的优化。在VAD中有两个指向后面元素——左右子树——的指针。树的根位于EPROCESS结构体的VadRoot域(NT 4.0下是偏移0x170)。当然,每一个进程都有自己的VAD 树。VAD的首部形式如下:

typedef struct vad_header {

void *StartingAddress;

void *EndingAddress;

struct vad *ParentLink;

struct vad *LeftLink;

struct vad *RightLink;

ULONG Flags;

}VAD_HEADER, *PVAD;

PPTE

Prototype Pte是又一级的线性地址转换并用于共享内存。假设有个文件映射到了几个(3个)进程的地址空间。PPTE表包含有PPTE,这些PPTE描述了加载到内存的文件的物理页。某些PPTE 可以有P位(其位置与含义与PTE/PDE的相同),而某些则没有,没有P位的有信息用来决定是从页来加载frame还是从映象文件来加载文件。所有三个进程的文件都映射在不同的地址上,对应于这些页的PTE的P位未设置,并且包含有文件页的PPTE的引用。这样,在转换映射到文件的线性地址的时候,在一号进程中发生异常14,VMM找到PTE,得到对PPTE的引用,现在可以直接“修正”相应的PTE,以使其指向属于文件的frame,这时必需从文件中加载frame。我给出未设置P位PTE的格式,在页表中其指向原型PTE。

PTE points to PPTE

+-----------------------------------------+-+---+-------------+-+

|3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1|1|0 0|0 0 0 0 0 0 0|0|

|1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1|0|9 8|7 6 5 4 3 2 1|0|

+-----------------------------------------+-+---+-------------+-+

| Address [7:27] |1|Un | Address |0|

| | |use| [0:6] | |

| | |d | | |

+-----------------------------------------+-+---+-------------+-+

*MmAccessFault

我们开始来研究一下MmAccessFault的伪代码。其原型:

NTSTATUS MmAccessFault (BOOL Wr,DWORD Addr, BOOL P)

参数的意义很明显:写入标志,发生异常的地址和页存在位。对于确定异常的原因,这些信息就足够了。根据Addr是属于内核地址空间还是用户地址空间,处理程序从两个执行分支中选择一个。第一种情况下的处理程序较为简单,跟踪ACCESS VIOLATION或是收回在Working Set中的页(MiDispatchFault)。若是用户空间的地址情况就就更为复杂一些。首先,如果PDE不在内存中则执行用于PDE的异常处理程序。然后,出现了一个分支。第一个分支——页存在。这表示要么是ACCESS VIOLATION,要么就是对copy on write的处理。第二个分支——处理清零页请求、ACCESS VIOLATION、页边界(GUARD)(堆栈增长)以及必须的对working set中页的回收。有趣的是,在大量发生page fault的时候,系统会增大working set的大小。在零PTE 的情况下,为确定状况,处理程序不得不使用VAD树来确定试图访问区域的属性。这些都是MiAccessCheck的工作,这个函数返回访问的状态。

一般情况下,异常处理程序的主要奠基工作是由MiDispatchFault函数执行的。它能更精确的确定状况并决定下一步的工作。

轮到MiDispatchFault了,它主要是基于一些更低级的函数:MiResolveTransitionFault、MiResolveDemandZeroFault、MiResolveDemandZeroFault、MiResolveProtoPteFault和MiResolvePageFileFault。从这些函数的名字可以明显看出,这个函数用于确定更为具体的情况:状态为'transition'(可能会很快回收入Working Set)的页应该是空白的frame,PTE指向PPTE 并且frame换出到相应的页面文件中。在与页面文件有关的和某些与PPTE有关的情况下,接着可能需要从文件中读取frame,此时函数返回值为0xc0033333,表示必须从文件中读取页。这在MiDispatchFault中是靠IoPageRead进行的。我们来更仔细的研究一下所提到的函数。我们从MiResolveDemandZeroFault开始。

如果看一下这个函数的伪代码,则可以轻易的明白它的工作逻辑。请求zero frame并且进程得到这个frame。这时执行函数MiRemoveZeroPage或是MiRemoveAnyPage。第一个函数从zero 页的链表中取一页。如果未能成功,则通过第二个函数选择任何一页。这样的话,该页就由MiZeroPhysicalPage来清零。最终,在MiAddValidPageToWorkingSet中,该清零的页被添加到工作集中(恰好,这个事实证明在分配内存时进程不能取得对未处理页的访问)。现在我们来研究一下更为复杂的情况——页位于页面文件中。

前面的伪代码需要一个结构体。在准备从文件中读取页的时候,会填充PAGE_SUPPORT_BLOCK 结构体。之后,对所有即将参与到操作中来的PFN进行以下操作:设置read in progress标志并在Misc域中写入PAGE_SUPPORT_BLOCK的地址(函数MiInitializeReadInProgressPfn)。最后,函数返回magic number 0xc0033333,表示随后要在IoPageRead调用中使用此结构体(恰巧,

IoPageRead被导出了,但是未公开的。从其伪码中可以很容易地得到其原型)。

typedef struct _PAGE_SUPPORT_BLOCK{ // size: 0x98

DISPATCHER_HEADER DispHeader; // 0 FastMutex

IO_STATUS_BLOCK IoStatusBlock; // 0x10

LARGE_INTEGER AddrInPageFile; // 0x18 (file offset)

DWORD RefCounter; // 0x20 (0|1) ???

KTHREAD Thread; // 0x24

PFILE_OBJECT FileObject; // 0x28

DWORD AddrPte; // 0x2c

PPFN pPfn; // 0x30

MDL Mdl; // 0x34

DWORD MdlFrameBuffer[0x10]; // 0x50

LIST_ENTRY PageSupportList; // 0x90 与MmInPageSupportList有关的链表

}PAGE_SUPPORT_BLOCK *PAGE_SUPPORT_BLOCK;

struct _MmInPageSupportList{

LIST_ENTRY PageSupportList;

DWORD Count;

}MmInPageSupportList;

函数MiResolvePageFileFault本身非常简单,除了填充相应的结构体并返回0xc0033333之外什么也不干。剩下的就是执行MiDispatchFault。这很合乎情理,如果还记得复用代码的原则的话。

还有一个不太复杂的函数MiResolveTransitionFault。对于状态为transition的frame还需要再多说几句。从这个状态中frame可以很快地返回到进程的Working Set中。

于是,剩下了最后一种情况——PROTO PTE。这种情况的处理函数也不太复杂,而且支撑其的基础我们已经讲过了。实际上还有一个函数与这种情况有关,这就是MiCompleteProtoPteFault,从MiDispatchFault中调用。要想理解这些函数的工作就去看一下伪代码。

07. section 对象

================

NT 中的section对象就是一块内存,这块内存由一个进程独有或几个进程共享。在Win32子系统中section就是文件映射(file mapping object)。我们来看一下section对象到底是什么。

section是NT下非常常用的对象,执行系统使用section来将可执行映象加载到内存中并用其来管理cache。section同时也用在向进程地址空间中映射文件。这时访问文件就像访问内存。section 对象,就像其它的对象一样,是由对象管理器创建的。高层次的信息告诉我们,对象的body中包含着以下类型的信息:section的最大值,保护属性,其它属性。什么是section的最大可访问值,这不说也知道。保护属性是用于section页的属性。其它section属性有表示是文件section 还是为空值(映射入页面文件)的标志,以及section是否是base的。base的section以相同

操作系统内存管理复习过程

操作系统内存管理

操作系统内存管理 1. 内存管理方法 内存管理主要包括虚地址、地址变换、内存分配和回收、内存扩充、内存共享和保护等功能。 2. 连续分配存储管理方式 连续分配是指为一个用户程序分配连续的内存空间。连续分配有单一连续存储管理和分区式储管理两种方式。 2.1 单一连续存储管理 在这种管理方式中,内存被分为两个区域:系统区和用户区。应用程序装入到用户区,可使用用户区全部空间。其特点是,最简单,适用于单用户、单任务的操作系统。CP/M和 DOS 2.0以下就是采用此种方式。这种方式的最大优点就是易于管理。但也存在着一些问题和不足之处,例如对要求内

存空间少的程序,造成内存浪费;程序全部装入,使得很少使用的程序部分也占用—定数量的内存。 2.2 分区式存储管理 为了支持多道程序系统和分时系统,支持多个程序并发执行,引入了分区式存储管理。分区式存储管理是把内存分为一些大小相等或不等的分区,操作系统占用其中一个分区,其余的分区由应用程序使用,每个应用程序占用一个或几个分区。分区式存储管理虽然可以支持并发,但难以进行内存分区的共享。 分区式存储管理引人了两个新的问题:内碎片和外碎片。 内碎片是占用分区内未被利用的空间,外碎片是占用分区之间难以利用的空闲分区(通常是小空闲分区)。 为实现分区式存储管理,操作系统应维护的数据结构为分区表或分区链表。表中各表项一般包括每个分区的起始地址、大小及状态(是否已分配)。

分区式存储管理常采用的一项技术就是内存紧缩(compaction)。 2.2.1 固定分区(nxedpartitioning)。 固定式分区的特点是把内存划分为若干个固定大小的连续分区。分区大小可以相等:这种作法只适合于多个相同程序的并发执行(处理多个类型相同的对象)。分区大小也可以不等:有多个小分区、适量的中等分区以及少量的大分区。根据程序的大小,分配当前空闲的、适当大小的分区。 优点:易于实现,开销小。 缺点主要有两个:内碎片造成浪费;分区总数固定,限制了并发执行的程序数目。 2.2.2动态分区(dynamic partitioning)。 动态分区的特点是动态创建分区:在装入程序时按其初始要求分配,或在其执行过程中通过系统调用进行分配或改变分区大小。与固定分区相比较其优点是:没有内碎

任务管理器里的各个进程

任务管理器里的各个进程 【Csrss】 这是Windows的核心部份之一,全称为Client Server Process。我们不能结束该进程。这个只有4K的进程经常消耗3MB到6MB左右的内存,建议不要修改此进程,让它运行好了【Ctfmon】 这是安装了WinXP(尤其是安装ofice XP)后,在桌面右下角显示的“语言栏”,如果不希望它出现,可通过下面的步骤取消:双击“控制面板”,“区域和语言设置”,单击“语言”标签,单击“详细信息”按钮,打开“文字服务和输入语言”对话框,单击下面“首选项”的“语言栏”按钮,打开“语言栏设置”对话框,取消“在桌面上显示语言栏”的勾选即可。不要小看这个细节,它会为你节省1.5MB到4MB的内存。 【dovldr32】 如果你有一个Creative SBLive系列的声卡,就可能击现这个进程,它占用大约2.3MB 到2.6MB的内存。有些奇怪的是,当我从任务栏禁止了这个进程后,通过DVD实验,并没有发生任何错误。但如果你将这个文件重新命名了,就会出现windows的文件保护警告窗口,而且Creative Mixer和AudioHQ程序加载出错。当然你希望节省一些内存,那么可以将它禁止。 【explorer】 这可不是Internet Explorer,explorer.exe总是在后台运行,它控制着标准的用户界面、进程、命令和桌面等,如果打开“任务管理器”,就会看到一个explorer.exe在后台运行。根据系统的字体、背景图片、活动桌面等情况的不同,通常会消耗5.8MB到36MB 内存不 【Idle】 如果你在“任务管理器”看到它显示99%的占用率,千万不要害怕,实际上这是好事,因为这表示你的计算机目前有99%的性能等待你使用!这是关键进程,不能结束。该进程只有16KB的大小,循环统计CPU的空闲度。 【IEXPLORE】/【iexplore】 这才是IE浏览器。当我们用它上网冲浪时,它占有7.3MB甚至更多的内存。当然,这个随着打开的浏览器窗口的增加而增多。但当关闭所有IE窗口时,它并不会从任务管理器消失,IEXPLORE.EXE依然在后台运行着,它的作用是加快我们再一次打开IE的速度。【Generic Host Process for Win32 Services】 如果你安装了ZoneAlarm以后,在连接Internet时ZonAlarm总是抱怨链接不到Internet,那么你就应该好好看看下面的文字。Svhost.exe就是Generic Service Host,意思就是说,它是其他服务的主机。如果你的Internet连接不工作了,很有可能是你禁止了一些必须的服务,比如如果你禁止了“DNS搜索”功能,那么当你输入https://www.360docs.net/doc/5f18793987.html, 时就不会连接上网,但如果输入IP地址,尽管还是可以上网,但实际上你已经破坏了上网冲浪的关键进程! 【msmsgs】 这是微软的Windows Messengr(即时通信软件)著名的MSN进程,在WinXP的家庭版和专业版里面绑定的,如果你还运行着Outlook和MSN Explorer等程序,该进程会在后台运行支持所有这些微软号称的很Cool的,NET功能等新技术。

windows进程管理实验报告

实验报告 课程名称:操作系统 实验项目:windows进程管理 姓名: 专业:计算机科学与技术 班级: 学号:

计算机科学与技术学院 计算机系 2019 年 4 月 23 日

实验项目名称: windows进程管理 一、实验目的 1. 学习windows系统提供的线程创建、线程撤销、线程同步等系统调用; 2. 利用C++实现线程创建、线程撤销、线程同步程序; 3. 完成思考、设计与练习。 二、实验用设备仪器及材料 1. Windows 7或10, VS2010及以上版本。 三、实验内容 1 线程创建与撤销 写一个windows控制台程序(需要MFC),创建子线程,显示Hello, This is a Thread. 然后撤销该线程。 相关系统调用: 线程创建: CreateThread() 线程撤销: ExitThread() 线程终止: ExitThread(0) 线程挂起: Sleep() 关闭句柄: CloseHandle() 参考代码: ; } 运行结果如图所示。 完成以下设计题目: 1. 向线程对应的函数传递参数,如字符串“hello world!”,在线程中显示。 2. 如何创建3个线程A, B, C,并建立先后序执行关系A→B→C。

实验内容2 线程同步 完成父线程和子线程的同步。父线程创建子线程后进入阻塞状态,子线程运行完毕后再唤醒。 相关系统调用: 等待对象 WaitForSingleObject(), WaitForMultipleObjects(); 信号量对象 CreateSemaphore(), OpenSemaphore(), ReleaseSemaphore(); HANDLE WINAPI CreateSemaphore( _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes _In_ LONG lInitialCount, _In_ LONG lMaximumCount, _In_opt_ LPCTSTR lpName ); 第一个参数:安全属性,如果为NULL则是默认安全属性 第二个参数:信号量的初始值,要>=0且<=第三个参数 第三个参数:信号量的最大值 第四个参数:信号量的名称 返回值:指向信号量的句柄,如果创建的信号量和已有的信号量重名,那么返回已经存在的信号量句柄参考代码: n"); rc=ReleaseSemaphore(hHandle1,1,NULL); err=GetLastError(); printf("Release Semaphore err=%d\n",err); if(rc==0) printf("Semaphore Release Fail.\n"); else printf("Semaphore Release Success. rc=%d\n",rc); } 编译运行,结果如图所示。

linux内存管理子系统 笔记

4-4 linux内存管理子系统 4-4-1 linux内存管理(参考课件) 物理地址:cpu地址总线上寻址物理内存的地址信号,是地址变换的最终结果 逻辑地址:程序代码经过编译后,出现在汇编程序中的地址(程序设计时使用的地址) 线性地址:又名虚拟地址,32位cpu架构下4G地址空间 CPU要将一个逻辑地址转换为物理地址,需要两步: 1、首先CPU利用段式内存管理单元,将逻辑地址转换成线性地址; 2、再利用页式内存管理单元,把线性地址最终转换为物理地址 相关公式: 逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器)(通用的) 16位CPU:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 线性地址=段寄存器的值×16+逻辑地址的偏移部分 物理地址=线性地址(没有页式管理) 32位CPU:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 线性地址=段寄存器的值+逻辑地址的偏移部分 物理地址<——>线性地址(mapping转换) ARM32位:逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 逻辑地址=段内偏移量(段基地址为0) 线性地址=逻辑地址=段内偏移量(32位不用乘以32) 物理地址<——>线性地址(mapping转换) ************************!!以下都是x86模式下!!********************************* 一、段式管理 1.1、16位CPU:(没有页式管理) 1.1.1、段式管理的由来: 16位CPU内部有20位地址总线,可寻址2的20次方即1M的内存空间,但16位CPU 只有16位的寄存器,因此只能访问2的16次方即64K。因此就采用了内存分段的管理模式,在CPU内部加入了段寄存器,这样1M被分成若干个逻辑段,每个逻辑段的要求如下: 1、逻辑段的起始地址(段地址)必须是16的整数倍,即最后4个二进制位须全是0 (因此不必保存)。 2、逻辑段的最大容量为64K。 1.1.2、物理地址的形成方式: 段地址:将段寄存器中的数值左移4位补4个0(乘以16),得到实际的段地址。 段偏移:在段偏移寄存器中。 1)逻辑地址=段基地址+段内偏移量(段基地址寄存器+段偏移寄存器) 2)由逻辑地址得到物理地址的公式为:(因为没有页式管理,所以这一步就得到了物理地址)物理地址PA=段寄存器的值×16+逻辑地址的偏移部分(注意!!)(段与段可能会重叠)

3.1 Windows“任务管理器”的进程管理

3.1 Windows“任务管理器”的进程管理 (实验估计时间:60分钟) 背景知识 实验目的 工具/准备工作 实验内容与步骤 背景知识 Windows 2000的任务管理器提供了用户计算机上正在运行的程序和进程的相关信息,也显示了最常用的度量进程性能的单位。使用任务管理器,可以打开监视计算机性能的关键指示器,快速查看正在运行的程序的状态,或者终止已停止响应的程序。也可以使用多个参数评估正在运行的进程的活动,以及查看CPU 和内存使用情况的图形和数据。其中: 1) “应用程序”选项卡显示正在运行程序的状态,用户能够结束、切换或者启动程序。 2) “进程”选项卡显示正在运行的进程信息。例如,可以显示关于CPU 和内存使用情况、页面错误、句柄计数以及许多其他参数的信息。 3) “性能”选项卡显示计算机动态性能,包括CPU 和内存使用情况的图表,正在运行的句柄、线程和进程的总数,物理、核心和认可的内存总数 (KB) 等。 实验目的 通过在Windows 任务管理器中对程序进程进行响应的管理操作,熟悉操作系统进程管理的概念,学习观察操作系统运行的动态性能。 工具/准备工作 在开始本实验之前,请回顾教科书的相关内容。 需要准备一台运行Windows 2000 Professional操作系统的计算机。

实验内容与步骤 1. 使用任务管理器终止进程 2. 显示其他进程计数器 3. 更改正在运行的程序的优先级 启动并进入Windows环境,单击Ctrl + Alt + Del键,或者右键单击任务栏,在快捷菜单中单击“任务管理器”命令,打开“任务管理器”窗口。 在本次实验中,你使用的操作系统版本是: Window 2000 5.00.2195 Service Pack 4 当前机器中由你打开,正在运行的应用程序有: Windows“任务管理器”的窗口由3个选项卡组成,分别是: 当前“进程”选项卡显示的栏目分别是 (可移动窗口下方的游标/箭头,或使窗口最大化进行观察) : 1. 使用任务管理器终止进程 步骤1:单击“进程”选项卡,一共显示了____个进程。请试着区分一下,其中: 系统 (SYSTEM) 进程有_____个,填入表3-1中。 表3-1 实验记录 映像名称用户名CPU内存使用

四川大学 操作系统上机实验 实验五 Windows虚拟存储器管理

实验报告 实验名称:Windows虚拟存储器管理 实验时间:2013年5月27日 实验人员:____郑笑凡___(姓名)__1143041243__(学号)____2011____(年级) 实验目的:1、了解Windows 2000/XP的内存管理机制,掌握页式虚拟存储技术。 2、理解内存分配原理,特别是以页面为单位的虚拟内存分配方法。 3、学会使用Windows 2000/XP下内存管理的基本API函数 实验环境:windows xp 实验步骤: 1、下载virtumem.cpp; 2、建立工程,将virtumen.cpp加入; 3、编译工程,观察结果,确信六种状态都出现至少一次,必要时可改程 序,方便观察结果; 4、看懂程序,按要求另写一段小程序; 5、编译,执行,观察结果。 6,总结。 实验陈述: 1、基础知识: pagefile.sys文件的位置在:__安装的系统盘根目录下____________________________________此文件的作用:____实现物理内存的扩展__________________________________________________ 改变此文件大小的方法:右击”我的电脑”,依次选择”属性”—“高级”—“性能选项”— “更改”_______________________________________ 虚拟地址空间中的页面分为:提交页面,保留页面,空闲页面 页面的操作可以分为:保留、提交、回收、释放、加锁 2、编程准备. 页面属性是在结构体MEMORY_BASIC_INFORMATION_的字段AllocationProtect 和字段中Protect体现出来的。 简述VirtualFree,VirtualPtotect,VirtualLock,VirtualUnlock,VirtualQuery的作用:_ VirtualFree:__释放虚存___________________________________________________ VirtualPtotect:_保留虚存_________________________________________________ VirtualLock:___加锁虚存_________________________________________________ VirtualUnlock:_解锁虚存________________________________________________ VirtualQuery:____查询虚存_______________________________________________ 3、编程 1)将virtumem.cpp加入工程,编译,执行。 是否能编译成功?是 请描述运行结果:

Windows下的进程管理和监控器分解

操作系统安全课程设计报告Windows下的进程管理和监控器

目录 操作系统安全课程设计报告 0 一、概述 (2) 1.设计主要完成的任务 (2) 2.解决的主要问题 (2) 二、设计的基本概念和原理 (2) 1.概念 (2) 2.原理 (2) 三、总体设计 (3) 1.功能模块 (3) 2.流程图 (3) 四、详细设计 (4) 主要功能的代码实现: (4) 五、完成的情况以及使用说明 (22) 六、总结 (33) 七、参考文献 (34)

一、概述 1.设计主要完成的任务 设计一个Windows或Linux下的进程管理与监控程序,要求该程序完成以下功能: (1)可获取当前正在运行的所有进程,包括进程PID、进程名称、CPU使用情况、当前用户名、内存占用量等; (2)能进一步获取各进程的所有线程情况; (3)能通过命令终止某个进程的执行,终止时能将其子孙进程全部终止; (4)要求界面友好。 2.解决的主要问题 我们的电脑需要我们去了解它的运行状况,掌握和管理它的进程,并对其异常情况给予操作和控制,任务管理器就像是我们了解和控制自己电脑运作的一个窗口,通过这个窗口我们可以了解到电脑所有进程运行状况,并对运行的进程加于管理和控制。本管理器设计比较简洁,操作灵活,使用简单,可以为我们管理和控制计算机的进程提供了一个简便的方法,是我们控制本计算机进程和了解计算机进程情况的良好助手。 二、设计的基本概念和原理 1.概念 在本实验中,启动进程管理器后,可以通过”获取进程”功能来获得本计算机启动的进程,以及与该进程相关的信息,其中包括的信息有:进程映像名称,进程开启的线程数,进程的PID以及进程的优先数,我们可以通过这些信息来了解计算机中每个进程的使用状况。同时我们可以在进程管理器上选中一个要终止的的进程,点击“终止进程”功能按钮,该进程被终止执行并退出进程列表,其中还包括了自动刷新的功能,此按钮实现的功能正如我们电脑任务管理器的“进程”功能,当电脑执行程序不能通过关闭窗口进行正常的关闭时,可以借助此办法来关闭进程。我们还可以通过这个进程管理器来启动新的进程,当我们要在进程管理器里启动新的进程时,只要点击“启动新进程”按键,则会弹出“打开进程”对话框,我们可以通过对话框里的“浏览”窗口选择要打开的新进程,这是任务管理器里没有实现的功能,通过这个功能我们在管理计算机时变得更加灵活方便,也使进程管理的功能更加完善。在退出此进程管理器时候,只要选择“退出”功能按钮则可关闭进程管理器,快速退出管理器的界面。 2.原理

Solaris 8内存管理机制研究

Solaris 8内存管理机制研究 吴海燕 戚丽 冯珂 摘 要:寻找性能瓶颈是性能分析中的一项重要任务,内存瓶颈的表现并不像CPU或磁盘那样直接,本文通过对Solaris 8内存管理机制的研究,给出了寻找Solaris 8系统内存瓶颈的方法。 关键词:Solaris 8,内存管理,性能优化 一、问题的提出 清华大学计算机与信息管理中心数据中心现有服务器近百台,其中包括了SUN Fire 15000、SUN Enterprise 5500、SUN Enterprise 5000等大型SUN服务器,Solaris 8是主流操作系统。为了对服务器的资源(如CPU、内存、磁盘、网络)的使用情况进行长期监控,建立性能优化(performance tuning)的基准值,我们开发了一套脚本程序定时采集系统运行参数。在长期的监控中,我们发现Solaris 8系统的空闲内存(freemem)呈现一个有趣的变化规律,如图1所示: 图1 空闲内存(freemem)变化图 图1是某Solaris 8系统(在下文中我们称之为15k-a)自2003年2月份以来的freemem 变化情况,横坐标是时间,纵坐标是freemem的数量,以8K字节为单位。15k-a配置是10路Super SPARCIII CPU,10GB物理内存。从上图可以看到在正常运行时,freemem应该是比较稳定的,15k-a主要是运行数据库,数据库在运行时会占用2G内存作为SGA区使用,因此在通常的负载下,freemem保持在6~7G之间是比较正常的。稳定一段时间后,

15k-a的freemem会持续走低,直到最低值,约为18893×8KMB,然后系统开始回收内存,我们就会看到freemem数量急剧上升。freemem的陡降都发生在凌晨1:00之后,检查系统作业发现每天1:00都会有一个数据库备份脚本开始运行:首先是用“exp”命令给数据库做逻辑备份,然后用“cp”命令把备份出来的文件拷贝到后备存储上。这两个命令都是正常退出,没有任何报错。开始时我们曾怀疑是有内存泄漏,当某一天freemem大幅攀升时,此怀疑被解除了,因为如果有内存泄漏,系统是无法将内存回收回来的。 对于一个物理内存为10GB的系统来说,如果空闲内存(freemem)真的减少到不到二百兆,那将存在着严重的问题。但奇怪的是系统的CPU使用率一直很低,所有进程的反应也很快,系统没有任何资源匮乏的迹象。如何解释这些问题呢,为此我们对Solaris 2.x 的内存管理机制进行了研究。 二、Solaris的内存管理机制 Solaris 8的内存管理为虚拟内存管理。[1]简单地说,虚拟内存就是进程看到比它实际使用的物理内存多得多的内存空间,对于64位的Solaris 8操作系统,进程可以通过8K 大小的段寻址访问2的64次方字节的内存空间,这种8K的段被称为页(page)。传统的UNIX通过进程(pagedaemon)完成虚拟地址和物理地址间的转换,在Solaris中这些是通过一个硬件-MMU(Memory Management Unit)-来实现的。在多处理器系统中,每个CPU 都有自己的MMU。Solaris 8的虚拟存储体系由系统寄存器、CPU CACHE、主存(RAM,物理内存)、外存(磁盘、磁带等)构成。 有两个基本的虚拟内存系统管理模型[2]:交换(swapping)和按需换页(demand paged)模型。交换模型的内存管理粒度是用户进程,当内存不足时,最不活跃的进程被交换出内存(swapping out)。按需换页模型的内存管理粒度是页(page),当内存匮乏时,只有最不经常使用的页被换出。Solaris 8结合使用了这两种内存管理模型,在通常情况下使用按需换页模型,当内存严重不足时,使用交换模型来进行内存释放。 与传统UNIX系统相比,Solaris虚拟内存系统的功能要丰富得多,它负责管理所有与I/O和内存相关的对象,包括内核、用户应用程序、共享库和文件系统。传统的UNIX系统V(System V)使用一个单独的缓冲区来加速文件系统的I/O, Solaris 8则使用虚拟内存系统来管理文件系统的缓存,系统的所有空闲内存都可以被用来做为文件I/O缓存,因为RAM的访问速度比磁盘快得多,所以这样做带来的性能提高是可观的。这也意味着在存在大量文件系统I/O的系统上,空闲内存的数量几乎是0。 了解系统内存被分配到了什么地方,系统在什么情况下进行内存整理是系统管理的重

操作系统实验之内存管理实验报告

学生学号 实验课成绩 武汉理工大学 学生实验报告书 实验课程名称 计算机操作系统 开 课 学 院 计算机科学与技术学院 指导老师姓名 学 生 姓 名 学生专业班级 2016 — 2017 学年第一学期

实验三 内存管理 一、设计目的、功能与要求 1、实验目的 掌握内存管理的相关内容,对内存的分配和回收有深入的理解。 2、实现功能 模拟实现内存管理机制 3、具体要求 任选一种计算机高级语言编程实现 选择一种内存管理方案:动态分区式、请求页式、段式、段页式等 能够输入给定的内存大小,进程的个数,每个进程所需内存空间的大小等 能够选择分配、回收操作 内购显示进程在内存的储存地址、大小等 显示每次完成内存分配或回收后内存空间的使用情况 二、问题描述 所谓分区,是把内存分为一些大小相等或不等的分区,除操作系统占用一个分区外,其余分区用来存放进程的程序和数据。本次实验中才用动态分区法,也就是在作业的处理过程中划分内存的区域,根据需要确定大小。 动态分区的分配算法:首先从可用表/自由链中找到一个足以容纳该作业的可用空白区,如果这个空白区比需求大,则将它分为两个部分,一部分成为已分配区,剩下部分仍为空白区。最后修改可用表或自由链,并回送一个所分配区的序号或该分区的起始地址。 最先适应法:按分区的起始地址的递增次序,从头查找,找到符合要求的第一个分区。

最佳适应法:按照分区大小的递增次序,查找,找到符合要求的第一个分区。 最坏适应法:按分区大小的递减次序,从头查找,找到符合要求的第一个分区。 三、数据结构及功能设计 1、数据结构 定义空闲分区结构体,用来保存内存中空闲分区的情况。其中size属性表示空闲分区的大小,start_addr表示空闲分区首地址,next指针指向下一个空闲分区。 //空闲分区 typedef struct Free_Block { int size; int start_addr; struct Free_Block *next; } Free_Block; Free_Block *free_block; 定义已分配的内存空间的结构体,用来保存已经被进程占用了内存空间的情况。其中pid作为该被分配分区的编号,用于在释放该内存空间时便于查找。size表示分区的大小,start_addr表示分区的起始地址,process_name存放进程名称,next指针指向下一个分区。 //已分配分区的结构体 typedef struct Allocate_Block { int pid; int size; int start_addr; char process_name[PROCESS_NAME_LEN]; struct Allocate_Block *next; } Allocate_Block; 2、模块说明 2.1 初始化模块 对内存空间进行初始化,初始情况内存空间为空,但是要设置内存的最大容量,该内存空间的首地址,以便之后新建进程的过程中使用。当空闲分区初始化

操作系统实验二Windows任务管理器的进程管理

实验二 Windows任务管理器的进程管理 一实验目的 1)在Windows 任务管理器中对程序进程进行响应的管理操作; 2)熟悉操作系统进程管理的概念; 3)学习观察操作系统运行的动态性能。 二实验环境 需要准备一台运行Windows XP操作系统的计算机。 三背景知识 Windows XP的任务管理器提供了用户计算机上正在运行的程序和进程的相关信息,也显示了最常用的度量进程性能的单位。使用任务管理器,可以打开监视计算机性能的关键指示器,快速查看正在运行的程序的状态,或者终止已停止响应的程序。也可以使用多个参数评估正在运行的进程的活动,以及查看CPU 和内存使用情况的图形和数据。 四实验内容与步骤 启动并进入Windows环境,单击Ctrl + Alt + Del键,或者右键单击任务栏,在快捷菜单中单击“任务管理器”命令,打开“任务管理器”窗口。 当前机器中由你打开,正在运行的应用程序有: 1) 实验二Windows 任务管理器的进程管理 2) 管理工具 3) 可移动磁盘(I:) Windows“任务管理器”的窗口由 5 个选项卡组成,分别是: 1) 应用程序 2) 进程 3) 性能 4)联网 5)用户 当前“进程”选项卡显示的栏目分别是(可移动窗口下方的游标/箭头,或使窗口最大化进行观察) : 1) 映像名称 2) 用户名 3) CPU 4)内存使用 1. 使用任务管理器终止进程 步骤1:单击“进程”选项卡,一共显示了33 个进程。请试着区分一下,其中:系统(SYSTEM) 进程有19 个,填入表2-1中。 表2-1 实验记录

映像名称用户名作用内存使用 Svchost.exe SYSYEM Windows服务主进程 4416K Service.exe SYSYEM 服务和控制应用程序 3272K Sqlserver.exe SYSYEM SQL 基础服务9580K LMS.exe SYSYEM Local Manageability service 2912K MDM.exe SYSYEM 进行应用软件进行排错 3424K Inetinfo.exe SYSYEM 支持微软Windows IIS网络 服务的排错 9780K Spoolsv.exe SYSYEM 管理所有本地和网络打印 队列及控制所有打印工作 5612K ati2evxx.exe SYSYEM 管理ATI Hotkey特性 4024K Svchost.exe SYSYEM Windows 服务主进程 24912K Svchost.exe SYSYEM Windows 服务主进程 5084K Service.exe SYSYEM 服务和控制应用程序 3476K Lsass.exe SYSYEM Local Security Authority Process 1736K Services.exe SYSYEM 服务和控制应用程序 5904K Winlogon.exe SYSYEM Windows 登陆应用程序1820K Csrss.exe SYSYEM Client Server Runtime Process 9492K Lsm.exe SYSYEM 本地会话管理器服务1156K Smss.exe SYSYEM Windows会话管理器408K System SYSYEM NT Kernel&System 2196K System Idle Process SYSYEM 处理空闲时间百分比 16K 服务(SERVICE) 进程有_ 4___个,填入表2-2中。 表2-2 实验记录 映像名称用户名作用内存使用 Svchost.exe LOCAL SERVICE Windows 服务主进程 4212K alg.exe LOCAL SERVICE 处理微软Windows网络连 接共享和网络连接防火墙 3808K Svchost.exe NETWOR KSERVICE Windows 服务主进程 3848K Svchost.exe NETWOR KSERVICE Windows 服务主进程 4660K 用户进程有__9____个,填入表2-3中。

JVM原理以及JVM内存管理机制

一、 JVM简介 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.exe来完成, 首先来说一下JVM工作原理中的jdk这个东西, .JVM 在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也就虚拟计算机. 操作系统装入JVM是通过jdk中Java.exe来完成。 通过下面4步来完成JVM环境. 1.创建JVM装载环境和配置 2.装载JVM.dll 3.初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例 4.调用JNIEnv实例装载并处理class类。 对于JVM自身的物理结构,我们可以从下图了解:

JVM的一个重要的特征就是它的自动内存管理机制,在执行一段Java代码的时候,会把它所管理的内存划分 成几个不同的数据区域,其中包括: 1. 程序计数器,众所周知,JVM的多线程是通过线程轮流切换并 分配CPU执行时间的方式来实现的,那么每一个线程在切换 后都必须记住它所执行的字节码的行号,以便线程在得到CPU 时间时进行恢复,这个计数器用于记录正在执行的字节码指令的地址,这里要强调的是“字节码”,如果执行的是Native方法,那么这个计数器应该为null; 2.

3. Java计算栈,可以说整个Java程序的执行就是一个出栈入栈 的过程,JVM会为每一个线程创建一个计算栈,用于记录线程中方法的调用和变量的创建,由于在计算栈里分配的内存出栈后立即被抛弃,因此在计算栈里不存在垃圾回收,如果线程请求的栈深度大于JVM允许的深度,会抛出StackOverflowError 异常,在内存耗尽时会抛出OutOfMemoryError异常; 4. Native方法栈,JVM在调用操作系统本地方法的时候会使用到 这个栈; 5. Java堆,由于每个线程分配到的计算栈容量有限,对于可能会 占据大量内存的对象,则会被分配到Java堆中,在栈中包含了指向该对象内存的地址;对于一个Java程序来说,只有一个Java堆,也就是说,所有线程共享一个堆中的对象;由于Java堆不受线程的控制,如果在一个方法结束之后立即回收这个方法使用到的对象,并不能保证其他线程是否正在使用该对象;因此堆中对象的回收由JVM的垃圾收集器统一管理,和某一个线程无关;在HotSpot虚拟机中Java堆被划分为三代:o新生代,正常情况下新创建的对象会被分配到新生代,但如果对象占据的内存足够大以致超过了新生代的容量限 制,也可能被分配到老年代;新生代对象的一个特点是最 新、且生命周期不长,被回收的可能性高;

关于windows任务管理器5个不错的替代选择

关于windows任务管理器5个不错的替代选择 ZD至顶网CIO与应用频道06月23日专栏:任务管理器可以帮助你查看系统进程,但不是你可以使用的唯一一个工具。下面名单中的应用可能更适合你。Windows任务管理器一直是一个非常方便的资源,可以用于监控运行中的进程,用于终止不能通过正常手段关闭的应用。不过,和Windows任务管理器一样,有很多其他应用可以替代任务管理器,提供多样的、与任务管理器相关的服务。本文将罗列这样5个应用。1、Security Task ManagerSecurity Task Manager (如图A)可能是这个名单中最不寻常的工具。与其任务管理器一样,这款应用为你显示系统中正在运行的进程。但是这款应用与众不同之处在于,显示的进程信息突出强调了安全性。这款应用不仅提供了病毒扫描链接,而且给每个进程分配了一个安全等级,帮助你确定哪些进程可能是恶意进程。图A右键点击一个进程,打开菜单,可以进入进程所在的文件夹。你还可以Google搜索这个进程,检查病毒,评论,查看其属性。评价进程让你可以将它标记为危险的或者安全的进程,并添加注释记录你的理由。Security Task Manager 售价29美元,有免费试用版可供下载。2、Task Manager FixTask Manager Fix(如图B)是一款修复Windows任务管理器的免费工具。我曾经考虑过不把这款应用列入这个名单

中,因为它不像其他应用,实际上它并不具备我会所谓的功能集。尽管如此,我认为它仍然有自己的优点。图B多年来,我已经遇到过很多会禁用任务管理器的恶意软件。一些恶意会攻击任务管理器,这样受害人就无法使用任务管理器终止与恶意软件相关的进程。这个简单的应用要求任务管理器符合这种情况。它包含一个按钮。点击这个按钮就可以恢复任务管理器到正常的状态。3、AnVir Task Manager ProAnVir Task Manager Pro(如图C)是一款功能丰富的任务管理器替代选择。这款工具提供了标签列出启动项、应用、进程、服务和日志条目。每个标签包含过滤机制,让各种条目显示或者隐藏。除了常用任务管理器功能之外,这款工具让你可以编辑系统启动,提供管理罗列项目的详细信息。事实上,这款应用提供了大约20多种你可以选择显示或者隐藏的项目。图C企业网盘前景看好售价49.95美元,有免费试用版可供下载,此外也有免费版本。4、Remote Task ManagerRemote Task Manager(如图D)类似于原生的Windows任务管理器,但它是针对管理远程系统中的任务而设计的。它提供了关于应用、进程、服务、设备和事件的信息。它还允许应用发布到远程系统中。图DRemote Task Manager售价40美元,有免费试用版可供下载。5、Free Extended Task ManagerFree Extended Task Manager(如图E)包括一系列标签,罗列了汇总信息、应用、进程、服务、性能、网络、用户和端口使

全面介绍Windows内存管理机制

全面介绍Windows内存管理机制及C++内存分配实例 文章整理: https://www.360docs.net/doc/5f18793987.html, 文章来源: 网络- - 本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用;根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制。 本文目的: 对Windows内存管理机制了解清楚,有效的利用C++内存函数管理和使用内存。本文内容: 本文一共有六节,由于篇幅较多,故按节发表。 1.进程地址空间 1.1地址空间 ?32|64位的系统|CPU 操作系统运行在硬件CPU上,32位操作系统运行于32位CPU 上,64位操作系统运行于64位CPU上;目前没有真正的64位CPU。 32位CPU一次只能操作32位二进制数;位数多CPU设计越复杂,软件设计越简单。 软件的进程运行于32位系统上,其寻址位也是32位,能表示的空间是232=4G,范围从0x0000 0000~0xFFFF FFFF。 ?NULL指针分区 范围:0x0000 0000~0x0000 FFFF 作用:保护内存非法访问 例子:分配内存时,如果由于某种原因分配不成功,则返回空指针0x0000 0000;当用户继续使用比如改写数据时,系统将因为发生访问违规而退出。 那么,为什么需要那么大的区域呢,一个地址值不就行了吗?我在想,是不是因为不让8或16位的程序运行于32位的系统上呢?!因为NULL分区刚好范围是16的进程空间。 ?独享用户分区 范围:0x0001 0000~0x7FFE FFFF 作用:进程只能读取或访问这个范围的虚拟地址;超越这个范围的行为都 会产生违规退出。 例子: 程序的二进制代码中所用的地址大部分将在这个范围,所有exe 和dll文件都加载到这个。每个进程将近2G的空间是独享的。 注意:如果在boot.ini上设置了/3G,这个区域的范围从2G扩大为3G: 0x0001 0000~0xBFFE FFFF。 ?共享内核分区 范围:0x8000 0000~0xFFFF FFFF 作用:这个空间是供操作系统内核代码、设备驱动程序、设备I/O高速缓存、非页面内存池的分配、进程目表和页表等。 例子: 这段地址各进程是可以共享的。

操作系统实验内存分配

精心整理西安邮电大学 (计算机学院) 课内实验报告 1. (1 (2 (3 原因,写出实验报告。 2.实验要求: 1)掌握内存分配FF,BF,WF策略及实现的思路; 2)掌握内存回收过程及实现思路; 3)参考本程序思路,实现内存的申请、释放的管理程序,调试运行,总结程序设计中出现的问题并找出原因,写出实验报告。

3.实验过程: 创建进程: 删除其中几个进程:(默认以ff首次适应算法方式排列) Bf最佳适应算法排列方式: wf最差匹配算法排列方式: 4.实验心得: 明 实验中没有用到循环首次适应算法,但是对其他三种的描述还是很详细,总的来说,从实验中还是学到了很多。 5.程序源代码: #include #include #include #include

#define PROCESS_NAME_LEN 32 //进程名长度 #define MIN_SLICE 10 //最小碎片的大小#define DEFAULT_MEM_SIZE 1024 //内存大小 #define DEFAULT_MEM_START 0 //起始位置 /*内存分配算法*/ #define MA_FF 1 #define MA_BF 2 #define MA_WF 3 /*描述每一个空闲块的数据结构*/ struct free_block_type { }; /* /* { }; /* /* void display_menu(); int set_mem_size(); void set_algorithm(); void rearrange(int algorithm); int rearrange_WF(); int rearrange_BF(); int rearrange_FF(); int new_process(); int allocate_mem(struct allocated_block *ab);

WindowsXP系统任务管理器使用技巧

任务栏管理器系统自带的一个很方便的软件。长久以来,大家也仅仅是习惯性的点击ctrl+alt+del来调出任务管理器了,然后取消某个失去相应的程序而已。其实任务管理器很强大的,它能很直观反映有系统的许多的东西,并且可以很方便的进行某些操作。在我们使用过程中有些技巧已经为大家所熟悉,但还有些技巧或许不是你都知道的,这里我给大家说一说任务栏管理器的一些应用或是技巧。看看能否对你将来使用电脑的时候有所帮助。一. 任务管理器的调出 1. 相信大多数朋友都会用左手按住左ctrl和alt,然后右手点击小键盘的del键来调出任务栏管理器。 2.单手按住左边的ctrl和alt,伸出一个手指来按文档控制的那个delete键也相当与ctrl+alt+del的功效。 3.你也可以选用右手按ctrl+alt+Esc也能调出任务管理器。 4.最简单的方法就是用鼠标在任务栏空白处点击右键,在弹出的菜单选择任务栏管理器即可。二. 任务管理器的外观 1. 这个问题曾经困扰着一些人,因为他们不小心把任务栏管理器弄成这个样子了,就象一个空白框,不知道怎么恢复了。其实很简单之所以能弄成这个样子,是因为你在任务管理器窗体上双击了左键。解决的方法也是相当的简单:再次双击就回复正常窗口的样子。 2. 选择不同的选项卡后再对窗体双击可以有不同的内容显示,这样你可以更加详细的对进程,或是网络cpu占用情况分析了。三. 任务栏管理器个选项卡的技巧 1. 应用程序栏:任意窗口的层叠,通过任务栏右键菜单中的“层叠窗口”命令,可以让所有打开的窗口层叠显示,但如果只是想让其中的几个窗口层叠显示出来,就要借助任务管理器了。在任务管理器的“应用程序”选项卡中选中想要层叠显示的程序窗口,然后单击右键,从菜单中执行“层叠”命令即可。此外,我们还可以随意最大化、最小化或前置指定的窗口。 2. 进程栏:在任务管理器的菜单―》查看―》选择列中可以定义要在进程栏里显示的内容,这里有许多专业的分析项目可以供你选择,比如虚拟内存大小。有些软件占用内存特别小的原因就是它用了不小的虚拟内存。默认的情况下,Windows XP任务管理器中的进程列表并不是按照名称进行排列的,查看起来不太方便,只要单击列表栏上方的文字标签,就可以让进程列表按序排列。例如单击“映像名称”标签,列表就会以进程名称的英文字母进行排序,单击“内存”标签,则可以按照内存使用量进行排序。 3. 用户栏:在这个栏目里,你可以注销已经登陆本机用户。如果你的权限足够,你可以断开任何登陆用户的登陆,如果有远程用户登陆本机。你可以选择发送消息给他。四. 任务栏管理器的升级其实任务栏管理器本身算的上一个不用安装的绿色程序了。你只需要把它拷倒你的机器上就能用了。最近网上流传着longhorn的任务管理器。这个版本的任务栏管理器比现在的windows xp版本任务栏管理器在进程那个选项里多了一个“映象路径”的功能,这样你就可以很方便的定位现在运行的进程位置。这一特性在我们对于可疑进程的鉴别上很有帮助。当然你可以用它来替换你现在使用的任务管理器。下载地址:https://www.360docs.net/doc/5f18793987.html,/down.php?id=26494&url=1使用方法:1、用附件中的三个文件覆盖Windowssystem32dllcache 下的同名文件。2、再用这三个文件覆盖Windowssystem32 目录下的同名文件,此时会弹出“Windows 文件保护”对话框,选择“取消”,然后选择“是”。然后你就可以按“Ctrl+Shift+Esc”或“Ctrl+Alt+Del”来使用新的任务管理器了。点击“进程”标签,然后在查看菜单下的“选择列。。。”中可以设置显示“命令行”和“映象路径”五. 任务管理器的一个特殊功能在点击菜单―》关机―》关闭选项的时候同时按住ctrl键的话。机器会在1秒左右关闭。更多请访问https://www.360docs.net/doc/5f18793987.html,/

相关文档
最新文档