Windows Embedded Compact 7中的内存管理(上)

Windows Embedded Compact 7中的内存管理

Windows Embedded CE1.05.0近十年的发展过程中,所支持的硬件平台、内部的实现机制以及显示界面等都产生了很多革命性的变化,唯有内存管理机制没有革新。作为支持虚拟内存的多任务操作系统,Windows Embedded CE内存容量小制约了应用程序的运行,特别是对于内存密集性或代码量较复杂的应用来说。

Windows Embedded CE 5.0之前的版本对程序的限制主要体现在两个“32”:最多并发支持32个进程,以及每个进程最多使用32MB的内存空间。早期或简单的嵌入式设备的内存占用量和进程数都不受印象。而且,Windows Embedded CE实现了丰富的内存管理API,支持虚拟内存分配、本地堆、独立堆、栈、以及内存映射文件等几乎所有内存资源。但是像占用大量内存多媒体播放器,以及需要许多简单进程组成的复杂控制系统,就受到了两个“32”的制约。

Windows Embedded CE 6.0开始,新的内存机制打破了两个“32”的约束,最多能同时支持32000个进程,而且每个进程的虚拟地址空间也提升到2GB

本章将介绍Windows Embedded CE 7.0的基本内存体系结构,包括不同类型的内存资源以及相关的操作函数,还将讲述Bootloader的功能和结构。

5.1Windows Embedded Compact 7中的RAMROM

任何一个完整系统的运行既需要动态保存数据的RAM,也需要引导系统启动的ROM。但是,Windows Embedded CERAMROM的功能与普通电脑还是存在一定的差异。

5.1.1RAM

与常见的RAM不同,Windows Embedded CERAM被划分为两个区域:对象存储区(Object Store)和程序存储区(Program Memory)。对象存储区类似于永久保留的虚拟RAM磁盘。为了应对设备的主电池短暂中断或故障,设备一般会采用备用电池来对RAM供电。这样,在系统被挂起或是执行软复位的时候,存放在对象存储区中的数据也不会丢失。当系统恢复正常时,操作系统会在RAM中寻找系统刚刚创建的对象存储区,并激活这些对象存储区中的数据。对于没有备用电池的RAM来说,设备可以使用基于蜂箱的注册表(Hive-based Registry)来保存系统设置。程序存储区类似普通电脑的RAM,它存储应用程序运行过程中的堆和栈等数据。

对象存储区和程序存储区之间没有固定的界限。用户可以通过系统提供的控制面板来管理两者之间的界限。在系统处于低可用内存的状态下,操作系统允许用户利用部分对象存储区来满足应用程序对RAM的需求。

5.1.2ROM

在基于Windows Embedded CE的设备中,ROM存储了整个的操作系统,还可能存在于操作系统绑定的应用程序。

存储在ROM中的模块有两种执行方式。如果存储在ROM中的模块没有被压缩,模块能够以现场执行(XIP)的方式直接运行。否则,操作系统先解压这个模块,再将其加载到RAM中。而且,与这个模块相关的数据也需要加载到RAM中来。ROM中的模块是否被压缩,是由OEM来控制的。

操作系统以现场执行的方式直接执行ROM中的程序,一方面能消除程序的代码和数据对RAM的消耗,节省短缺的RAM空间;另一方面省略了程序从ROM复制到RAM的流程,缩短了程序执行的时间。

对于存储在对象存储区或是闪盘上的应用程序,操作系统不会采用现场执行的方式执行这些能长期保存的代码,而是加载到RAM中运行。

5.2虚存

跟基于Win32的操作系统类似,Windows Embedded CE采用基于分页的虚拟内存管理。在虚拟内存系统中,每个进程拥有自己独立的虚拟地址空间。进程的虚拟地址与设备的物理地址之间不是直接对应的。操作系统的内存管理单元负责各个进程的虚拟地址与设备上唯一的物理地址空间建立映射。不同嵌入式设备的物理地址存在较大的差异。应用程序在虚拟地址空间可以不考虑这些差异性,而交由操作系统来管理,保证了应用程序的通用性和可移植性。虚拟内存的利用,既保证了各个进程的隔离性,互不干扰,也方便了系统对内存的统一管理。

5.2.1Windows Embedded Compact 7中的内存模式

Windows Embedded CE 5.0相比,Windows Embedded CE 6.07仍采用虚拟内存管理,但是在虚拟地址空间的管理和分布上发生了革命性的变化。新的操作系统架构以及新的虚拟地址空间架构,使得Windows Embedded Compact 7能够最多并发支持32000个进程,而每个进程独立的地址空间也有32MB提升到2GB的容量。

为了能够理解Windows Embedded Compact 7的内存架构带来的优势,下面先介绍Windows Embedded CE 5.0的虚拟地址空间结构。

5.2.2Windows Embedded CE 5.0虚拟地址空间

Windows Embedded CE 5.0是32位的所有进程统一的虚拟地址空间,也就是虚拟空间的容量是4GB。跟Windows XP一样,顶端的2GB地址空间被系统保留,作为操作系统内核专用。而剩余的低端2GB地址空间被划分为多个区。这部分低端的地址空间有接近一半的空间被称为大内存区域,主要用于分配给内存映射文件使用。低2GB的地址空间如图5.1所示。

紧接着大内存区域的虚拟地址空间是31个应用槽。每个应用槽存储了当前运行进程的虚拟地址镜像。最低位的64MB空间,更精确地说,是32MB空间,备份了当前运行线程所在进程的应用槽。

这个基于槽的架构,构成了两个“32”的约束。整个虚拟地址空间只有31个可用的应用槽,而且每个槽的大小为32MB的空间,因此系统最多只能同时支持31个应用进程以及1个位于高端2GB空间的内核进程,共32个进程。

最低位64MB的地址空间是系统当前运行环境的缩影,这个64MB地址空间详细的分布如图5.2所示,其中包括了32MB的动态链接库空间。最低32MB的空间是进程运行过程中分配的空间,包含了程序段、静态数据段、堆及栈等各种类型的内存空间。而高32MB空间被称为“应用槽1”,是所有应用程序共享的空间,其中存储了程序常用的动态链接库。这样,程序不需要重复加载这样动态库,节省了宝贵的内存空间。在Windows Embedded CE 5.0中。一个应用程序被限制在虚拟内存空间它自己的32MB应用槽和32MB的“应用槽1”中。

在最低的32MB地址空间中,最低64KB空间为所有应用程序保留,应用程序的代码被映射到64KB以上的区域,即从0x10000地址开始。应用程序的文件映像包括了代码、静态数据以及资源段,依次从低到高映射到相应的虚拟地址。在应用程序启动的时候,代码段不会被立刻加载进来。只有在需要执行这些代码的时候,才会被加载进来。

只读静态数据段和可读写静态数据段通常只占有很少的页面,它们都是以页为单位进行排列的。跟代码段一样,只有在使用它们的时候,内存管理单元才会为这些段在RAM中分配相应的页面。应用程序的资源段也是只读的,也是运行过程中被动态加载到RAM中。

堆是一段连续的较大的虚拟地址空间。应用程序在堆中可以动态地分配、释放所需大小的内存块。引导程序保留了大量的页,满足应用程序通过调用mallocnew等函数分配内存。

应用程序的栈是从高地址向低地址方向增长的,里面保存了程序运行过程中的局部变量、函数调用时的上下文等信息。同一个进程中的线程共享同一个虚拟地址空间,但是拥有各自的栈空间。如果进程拥有多个线程,那么应用程序的地址空间会保留多个栈空间。

除了上述内存空间,系统中仍未被使用的地址空间被称为空闲虚拟空间,它根据应用程序的不同而动态变化。

5.2.3Windows Embedded Compact 7虚拟地址空间

为了打破两个“32”的约束,Windows Embedded CE 6.07改变了以往的统一的内存虚拟地址空间。每个进程都能独立拥有低端的2GB虚拟地址空间,而不是所有的进程共享同一个2GB虚拟地址空间,如图5.3所示。

Windows Embedded CE 5.064MB的地址空间一样,低端的2GB地址空间也主要划分为两个区域:高端的1GB地址空间存放的是共享的数据或是作为特殊用途,而低端的1GB地址空间就是程序的代码和程序运行过程中分配的内存空间,如堆、栈等。这个2GB的地址空间映射如图5.4所示。

地址0x40000000以下的这部分虚拟地址空间的分布与Windows Embedded CE 5.0中低32MB的地址空间分布一样,只是大小有所变化,在此不作详述。

从地址0x0000000开始的512MB空间,是动态链接库的存储区域。这个区域包括了程序运行过程中加载动态库的代码和只读数据。跟Windows Embedded CE 5.0一样,动态链接库所占有的区域是被所有进程共享的。在此,不同进程中的相同动态链接库都会被加载到相同的地址,来达到在不同的虚拟地址空间共享同一动态库的目的。与Windows Embedded CE 5.0的动态链接库存储区不同之处,在于这里的动态链接库是从低地址往高地址加载的,不再是从高地址到低地址的方式了。

在动态链接库区域之上,从地址0x60000000开始的256MB空间用于分配给RAM备份的内存映射文件。RAM备份的内存映射区,也就是内存映射对象或是内存映射文件,实际上并没有一个真实的文件来保存对象中的数据。内存映射对象主要是用于进程间通信。为了向后兼容,如果一个内存映射对象在多个进程中被分配,它们都被映射在相同的地址。如果进程打开了一个真实的文件来进行内存映射,那么这个内存映射文件的地址在最低的1GB地址空间中分配。

从地址0x70000000开始的255MB空间用于操作系统和应用程序进行通信。这个区域只能被操作系统进行修改,而应用程序只能读取这个区域的值。而最高位的1MB空间作是预留的保护区域,不能被任何进程访问。

5.2.4内存状态查询函数

程序开发人员要开发一个高效的程序,首先必须弄清楚程序所运行平台的特征,包括了可用内存信息、处理器信息以及平台的架构等。

从系统资源角度出发,Windows Embedded Compact 7主要提供了两个函数接口,分别是GetSystemInfoGlobalMemoryStatus函数。其中,GetSystemInfo函数主要提供系统微处理器的信息,而GlobalMemoryStatus函数显示了系统的物理内存信息。下面对这两个函数的参数和返回值作详细的阐述。

一、函数GetSystemInfo介绍

函数GetSystemInfo的原型如下:

VOID GetSystemInfo (

LPSYSTEM_INFO lpSystemInfo

);

它的参数是一个指向SYSTEM_INFO结构的指针,返回值为空,即系统的信息存储在lpSystemInfo所指向的SYSTEM_INFO结构中。

结构体SYSTEM_INFO描述了当前系统的状态,包括了处理器的类型、页面的大小、内存的地址信息,以及OEM厂商的标识符。该结构定义如下:

typedef struct  _SYSTEM_INFO{

union {

  DWORD dwOemId;

  struct {

    WORD wProcessorArchitecture;

    WORD wReserved;

  };

};

DWORD dwPageSize;

   LPVOID lpMinimumApplicationAddress;

LPVOID lpMaximumApplicationAddress;

DWORD dwActiveProcessorMask;

DWORD dwNumberOfProcessors;

  DWORD dwProcessorType;

   DWORD dwAllocationGranularity;

WORD wProcessorLevel;

WORD wProcessorRevision;

} SYSTEM_INFO, *LPSYSTEM_INFO;

dwOemId可用于标识厂商的信息,在这里属于保留域。

wProcessorArchitecture域表示系统微处理器的架构。它可选的值包括:

PROCESSOR_ARCHITECTURE_INTEL

PROCESSOR_ARCHITECTURE_MIPS

PROCESSOR_ARCHITECTURE_UNKNOWN

PROCESSOR_ARCHITECTURE_ARM

这几个值分别代表Intel使用的X86架构、MIPS架构、未知架构和ARM架构。不同架构所使用的指令集不一样。

wReserved也属于保留域。

dwPageSize代表了页面的大小,也就是分页保护和页面提交的粒度。它也是虚拟内存分配函数VirtualAlloc中使用的页面大小。

lpMinimumApplicationAddresslpMaximumApplicationAddress分别代表了应用程序和动态链接库所能访问的最小的和最大的内存地址。

dwActiveProcessorMask用于标识系统中处理器的数量。其中,第0位代表处理器0,第31位则代表处理器31dwNumberOfProcessors表示系统中处理器的个数。

dwProcessorType域说明了处理器的类型。这个域已经不再重要。现在,wProcessorArchitecturewProcessorLevelwProcessorRevision这三个域决定了处理器类型。这个域可选的值包括如下:

PROCESSOR_INTEL_386

PROCESSOR_INTEL_486

PROCESSOR_INTEL_PENTIUM

PROCESSOR_INTEL_PENTIUMII

PROCESSOR_MIPS_R4000

PROCESSOR_STRONGARM

PROCESSOR_ARM720

PROCESSOR_MIPS_R5000

dwAllocationGranularity域指出了虚拟内存分配的粒度。例如,函数VirtualAlloc只分配一个字节的大小,但是系统为此保留的虚拟内存地址空间的大小为dwAllocationGranularity。一般而言,这个域的大小是64KB

wProcessorLevel域代表了处理器具体的型号(即处理器信息中的model),是整个处理器架构中该处理器的型号。

如果wProcessorArchitecture域的值为PROCESSOR_ARCHITECTURE_INTEL, wProcessorLevel可选的值为:

描述

4

Intel 80486

5

Pentium

如果wProcessorArchitecture域的值为PROCESSOR_ARCHITECTURE_ARM, wProcessorLevel可选的值为:

描述

4

ARM version 4

5

ARM version 5

6

ARM version 6

7

ARM version 7

如果wProcessorArchitecture域的值为PROCESSOR_ARCHITECTURE_MIPS, wProcessorLevel可选的值为:

描述

3

MIPS R3000

4

MIPS R4000

5

MIPS R5000

wProcessorRevision域表明了处理器的步进模式。不同处理器架构下处理器的步进模式如表5.1所示。

处理器架构

描述

Intel 80386 or 80486

格式类似于xxyz

如果xx的值为0xFF,那么(– 0xA)代表了处理器的型号,z是处理器步进的标号。

如果x的值不是0xff,那么(xx + ‘A’)达标了步进的值,而yz表明小步进的值。

Intel Pentium, Cyrix, or NextGen 586

格式类似于xxyyxx代表了处理器的型号,而yy代表了步进的值。

MIPS

格式类似于00xxxx代表了处理器的修订号。

ARM

值属于116的范围中,具体的类型参见ARM处理器的手册。

二、函数GlobalMemoryStatus介绍

函数GlobalMemoryStatus的原型如下:

void GlobalMemoryStatus(

  LPMEMORYSTATUS lpBuffer

);

该函数主要获取系统的物理和虚拟内存信息。通过这个函数,用户可以确定当前状态下应用程序可以使用且不影响其他程序的内存量。另外,这个函数得到的信息是当前时刻下系统的内存状态,具有瞬时性,即不能保证连续两次调用此函数得出的结构是一样的。

函数的参数是指向结构体MEMORYSTATUS的指针,返回值为空。查询结构的值存储在MEMORYSTATUS结构体中。MEMORYSTATUS结构体的定义如下:

typedef struct _MEMORYSTATUS {

  DWORD dwLength;

  DWORD dwMemoryLoad;

   DWORD dwTotalPhys;

  DWORD dwAvailPhys;

   DWORD dwTotalPageFile;

   DWORD dwAvailPageFile;

   DWORD dwTotalVirtual;

   DWORD dwAvailVirtual;

} MEMORYSTATUS, *LPMEMORYSTATUS;

dwLength域指定了MEMORYSTATUS结构体的长度,以字节为单位。在调用函数GlobalMemoryStatus之前,这个域必须初始化为sizeof(MEMORYSTATUS)

dwMemoryLoad域是一个范围在0100之间的不确定的值。它用来表示当前内存的使用状态。值为0表示内存的利用率为0,而值100表示内存被全部利用。

dwTotalPhys域和dwAvailPhys域分别表示当前系统中总共的物理内存大小和实际可用的物理内存大小,以字节为单位。

dwTotalPageFile域和dwAvailPageFile域指明了当前页面文件(paging file)的状态。如果系统不支持页面文件,这些参数总是0。这两个域都是以字节为单位的。

dwTotalVirtual域和dwAvailVirtual域指明了总共的和可用的可被应用程序存取的虚拟内存页的数量。

5.2.5Windows Embedded Compact 7中的分页式虚拟存储

与其它现代操作系统一样,Windows Embedded Compact 7操作系统采用了分页式虚拟存储。在分页式虚拟存储中,系统内存的分配以页作为基本管理单元。页面的大小默认为4098字节,即4KB

在前文提到,Windows Embedded Compact 7的内核进程使用高端的2GB虚拟地址空间,而低端的2GB地址空间为每个单独的进程所拥有。当应用程序申请内存时,系统在该进程的虚拟地址空间中为之分配一个虚拟内存,但是并不分配实际的物理内存。只有当应用程序首次存取一个页面的时候,系统的内存管理单元为每个虚拟内存页面分配对应的物理内存页面,并将这个对应关系保存在页表中。内存管理单元操作的粒度是一个页面。之后,应用程序对虚拟内存地址的访问,都通过硬件或软件实现的转换后援缓存器(TLB)转换为对应的物理内存地址。

这种分页式虚拟存储能带来几个好处:

每个进程能拥有很大容量的虚拟内存;

消除因虚拟地址空间大小而产生的对进程数量的限制;

进程间的隔离和保护;

尽量减少对CPU的依赖;

有效地分配虚拟地址空间;

TLB失效后的高效处理。

虚拟内存页可以处在三种状态:自由(free),保留(reserved),或被提交(committed)。自由页处于空闲状态,可被自由分配。保留页是虚拟地址已经被保留,并且不能被操作系统或进程中的其他线程重新分配。保留页不能用在别处,但是它同样不能被当前程序使用,因为它没有被映射到物理内存。要想执行映射,它必须被提交。提交的过程,就是系统的内存管理单元为虚拟内存页面分配相应数目的物理内存页面,并将信息保存在页表中。

5.2.1 与虚拟存储相关的函数

对于应用程序开发者来说,他们对内存的操作都是以虚拟地址的形式来完成的。应用程序调用虚拟内存的API接口来操作内存,包括了对虚拟内存的分配、释放、状态查询等。这种函数主要由VirtualAllocVirtualFreeVirutalProtectVirtualQuery组成。

一、函数VirtualAlloc介绍

函数VirtualAlloc的功能是为进程保留或提交一段虚拟内存空间,而且这片内存的数据会初始化为0。该函数的原型如下:

LPVOID VirtualAlloc(

  LPVOID lpAddress,

  DWORD dwSize,

  DWORD flAllocationType,

  DWORD flProtect

);

函数的返回值是分配到的虚拟内存区域的起始地址。如果函数调用发生错误,则返回NULL。函数的参数包括了程序指定的起始虚拟地址,以及申请空间的大小等,下面作详细描述。

lpAddress域指向分配要分配内存区域的起始地址。如果这片内存正被保留,那么这个地址向下对齐到下一个64KB;如果这个内存已经被保留,而且正在被提交,那么这个地址向下对齐到下一个页面,即4kB。如果这个参数是NULL,那么系统决定分配内存区域的位置。

dwSize域指定了要分配或保留域的大小,是以字节为单位的。如果lpAddress域是NULL,那么这个域向上对齐到下一个页面的起始地址。

flAllocationType域指定了分配的类型。可选的参数和对应的描述如下:

描述

MEM_COMMIT

在内存中或是磁盘上的分页文件中分配物理页面;如果待提交的页面已经被提交,函数不会返回失败。

MEM_RESERVE

为进程保留一段虚拟地址空间,但是不分配对应的物理内存。这段空间不能被其他的地址空间分配操作使用,例如mallocLocalAlloc函数。被保留的页面仍能通过函数VirtualAlloc提交。

MEM_RESET

不支持。

MEM_TOP_DOWN

从最高的虚拟地址开始分配。但是这个标志在Windows Embedded Compact中被忽略。

flProtect域指定了访问控制的类型。可选的参数和对应的描述如下:

描述

PAGE_EXECUTE

允许对已提交页面只执行运行操作,即区域中包含了可执行的代码。

PAGE_EXECUTE_READ

允许对已提交页面执行运行和读操作,而不能执行写操作。

PAGE_EXECUTE_READWRITE

允许对已提交页面执行运行、读以及写操作。

PAGE_GUARD

这段区域中的页面设置为受保护页面。对受保护页面的读或写操作都会产生STATUS_ACCESS_VIOLATION异常,而且页面的受保护状态会被取消。

它不能与标志PAGE_NOACCESS同时使用。

PAGE_NOACCESS

禁止所有对已提交页面的访问。对这些页面的读、写或运行操作都会出发访问出错异常。

PAGE_NOCACHE

允许不缓存已提交的页面。它不能与PAGE_NOACCESS同时使用。

PAGE_READONLY

只允许对已提交页面执行读操作。

PAGE_READWRITE

允许对已提交页面执行读或写操作。

二、函数VirtualFree介绍

函数VirtualFree的功能在于将进程内的一段虚拟地址空间释放掉,或者是取消提交。函数的原型如下:

BOOL VirtualFree(

  LPVOID lpAddress,

  DWORD dwSize,

  DWORD dwFreeType

);

函数的返回值为0表示执行失败,不为0表示执行成功。另外,通过函数GetLastError可以获取失败的详细信息。函数的参数包括了待释放或取消提交的起始虚拟地址、空间的大小,以及释放的类型。

lpAddress域指向这片内存区域的起始虚拟地址。如果dwFreeType域的值为MEM_RELEASE,那么这个地址必须是函数VirtualAlloc的返回值。

dwSize域指定了这片内存区域的大小。如果dwFreeType域的值为MEM_RELEASEdwSize的值必须为0

dwFreeType域描述了释放或取消提交操作的类型,具体的类型值与描述如下:

描述

MEM_DECOMMIT

取消提交这片页已经被提交的内存区域。如果页面没有被提交,函数返回值不会出错。

MEM_RELEASE

释放这篇被保留的内存区域。dwSize域的值必须为0,否则返回错误。

三、函数VirtualProtect介绍

函数VirtualProtect的功能在于改变进程的虚拟地址空间中已提交页面的访问权限。它的函数原型如下:

BOOL VirtualProtect(

  LPVOID lpAddress,

  DWORD dwSize,

  DWORD flNewProtect,

  PDWORD lpflOldProtect

);

函数的返回值为0表示执行失败,不为0表示执行成功。另外,通过函数GetLastError可以获取失败的详细信息。函数的参数包括了需改变权限内存区域的起始虚拟地址、空间的大小,以及相关的权限。

lpAddress域指向这片内存区域的起始虚拟地址。这个内存区域内的所有页面必须都是通过函数VirtualAlloc一次分配得到的,而不是两次或多次调用VirtualAlloc分配得到的。

dwSize域指定了这片内存区域的大小。

flNewProtect域指定了新的访问控制权限。它可以选择的值包括了PAGE_EXECUTEPAGE_EXECUTE_READPAGE_GUARDPAGE_NOACCESSPAGE_NOCACHE以及PAGE_READONLY

lpflOldProtect域是一个长指针,指向这片内存区域中第一个受保护页面的访问控制属性。如果这个值为NULL或是指向不合法的变量,这个函数执行失败。

四、函数VirtualQuery介绍

函数VirtualProtect的功能在于查询进程的虚拟地址空间中页面的状态。它的函数原型如下:

DWORD VirtualQuery(

  LPCVOID lpAddress,

  PMEMORY_BASIC_INFORMATION lpBuffer,

  DWORD dwLength

);

函数的返回值是查询结果大小的字节数。

lpAddress域指向区域开始查询的地址。

dwLength域指定查询结果的大小,值为PMEMORY_BASIC_INFORMATION结构的大小。

lpBuffer域是一个指向结构体MEMORY_BASIC_INFORMATION的指针,这个结构体保存了所查询页面的状态。结构体MEMORY_BASIC_INFORMATION的定义如下:

typedef struct _MEMORY_BASIC_INFORMATION {

  PVOID BaseAddress;

  PVOID AllocationBase;

  DWORD AllocationProtect;

  DWORD RegionSize;

  DWORD State;

  DWORD Protect;

  DWORD Type;

} MEMORY_BASIC_INFORMATION;

typedef MEMORY_BASIC_INFORMATION *PMEMORY_BASIC_INFORMATION;

MEMORY_BASIC_INFORMATION 结构的第一个字段是BaseAddress,是传递给VirtualQuery函数的一个地址。AllocationBase字段包含使用 VirtualAlloc函数分配的区域的基地址,AllocationProtect字段包含区域原来被分配时的保护属性。RegionSize字段包含从传递给VirtualQuery的指针开始到一系列具有相同属性的页为结尾的区域大小。State字段包含区域中页的状态-自由,保留,提交。Protect字段包含了页面的访问控制权限。Type字段可以包含MEM_PRIVATE标志,指明该区域包含应用程序私有的数据;MEM_MAPPED指明该区域被映射为一个内存映射文件;MEM_IMAGE指明该区域被映射为一个EXEDLL模块。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡耀文

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值