《windows核心编程》 在应用程序中使用虚拟内存

简介:

Microsoft Windows 提供了以下三种机制来对内存进行操控:

  • 虚拟内存 最适合用来管理大型对象数组或大型结构数组
  • 内存映射文件 最适合用来管理大型数据流(通常是文件),以及在同一台机器上运行多个进程之间共享数据
  •  最适合管理大量小型对象

 

本篇只讨论第一种方式 虚拟内存。

15.1 预订地址空间区域

可以使用VirtualAlloc函数来预订进程中的地址空间区域
LPVOID WINAPI VirtualAlloc(
  __in_opt  LPVOID lpAddress,
  __in      SIZE_T dwSize,
  __in      DWORD flAllocationType,
  __in      DWORD flProtect
);
lpAddress :想要预订地址空间的哪一块,如果要在进程地址空间第50MB的地方分配区域。我们要传52 428 800(50*1024*1024)给pvAddress参数。系统始终按分配粒度的整数倍来分配的因此如果我们想要在19668992(300*65536+8192)的地方预订区域,那么系统会向下取整到64整数倍,也就是19660800(300*65536)然后取整后的地址预订区域。如果VirtualAlloc能满足我们的要求,那么它会预订一块区域并返回该区域的基地址。如果我们还给pvAddesss指定了参数,那么,它的返回值就等于我们传给pvASddress参数值向下取整到64KB的整数倍
dwSize: 指定我们想要分析区域的大小,以字节为单位。由于系统始终都根据cpu页面大小整数倍来预订区域,因此如果我们的页面大小为4KB,8KB或16KB的机器上预订62 KB的区域的话,那么最终得到的区域大小为64KB 
flAllocationType:是预订区域还是调拨物理存储器,如果是预订就要传 MEM_RESERVE为参数
如果打算预订一块区域,并且用很长时间,那我们可能会希望系统从尽可能高的内存地址来预订。这样可以防止进程地址空间的中间预订区域,从而避免可能会引起内存碎片。
fdwProtect:给区域指定保护属性。
如果应用程序在非统一内存访问的机器上运行,我们可以调用VirtualAllocExNuma函数来强制系统在某个节点的物理内存中分配一部分虚拟内存
15.2 给区域调拨物理存储器、
在预了区域之后,我们还需要给给区域调拨物理存储器,这样才能访问其中的内存地址。系统会从页交换文件中来调拨物理存储器给区域。在调拨物理存储器时,起始地址始终都是页面大小的整数倍,整个大小也是页面大小的整数倍
调拨物理存储器,我们必须再次调用VirtualAlloc。但这次我们会传 MEM_COMMIT来作为第二个参数fdwAllocationType的值
在已预订的区域中,我们“必须”告诉VirtualAlloc要调拨多少物理存储器给哪里。这是通过pvAddress和dwSize来指定的。前者表示想要调拨物理存储器给哪个内存地址,后来表示物理存储器的数量。以字节为单位。
15.3 同时预订和调拨物理存储器
PVOID pvMem = VirtualAlloc(NULL,99*1024,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE)
15.4 何时调拨物理存储器
何时调拨物理存储器是一个问题,例如我们正在实现一个电子表格的程序,它支持200行,256。如果一个单元格是一个CELLDATA结构的话,如果这一个结构頕128字节,那么这个二维数组需要 200 * 256 * 128 的字节的物理存储器。那么如果一打开程序就去调拨,明显会頕用大量的物理存储器。尤其是因为用户经常只用一两个单元格的时候,那么这种调拨方法明显是浪费
虚拟内存技术为我们提供了方案:
1.预订一块足够大的区域来容纳CELLDATA数组。只预订根本不会消耗物理存储器
2.当用户某个单元格输入数据时,首先确定CELLDATA的内存地址。当然没有调拨,会引发访问违规
3.给第二步中的内存地址调拨足够的物理存储器。
4.设置CELLDATA结构成员的内容
虚拟内存技术存在一个问题是:我们必须确定什么时候需要调拨物理存储器。
有以下四种方法来确定是否需要给区域中的某一部分调拨物理存储器
1.总是尝试调拨,这种该当的缺点是每次对CELLDATA进行修改时,要多调用一次 VirtualAlloc。
2.使用VirtualQuery来判断是否给CELLDATA调拨过了。这种方法其实比第一种方法还糟糕:由于额外调用了VirtuaQuery函数,它不但增加了程序的大小,而且还降低了程序的性能
3.记录哪些被调拨过。这样来实时调拨
4.使用结构化异常处理------最佳方案。让程序底图方法内存异常的时候,调拨。
15.5 撤销缺氧物理存储器及释放区域
要撤销调拨给区域的物理存储器,或是释放地址空间中的一整块区域,可以调用
VirtualFree函数。
如果进程不再需要访问区域中的物理存储器,那么我们只需要调用VirtaulFree一次,就能够释放整个区域以及调拨给该区域的物理存储。我们必须传MEM_RELEASE给fdwFreeType来告诉系统撤销调拨给该区域的所有物理存储器,并释放区域。
如果想要撤销区域的一部分,我们只需要给pvAddress传地址,然后dwSize传大小,fdwFreeType传MEM_DECOMMIT就行
15.5.1何时撤销调拨物理存储器
15.6 改变保护属性

15.7 改变物理存储器的内容

当我们修改物理存储页中的内容时,系统会尽量把改动保持在内存中。但是,当应用程序在运行的时候,系统可能需要从exe文件,或dll文件或页交换文件中载入新的页面到内存里。为了满足最近的载入请求,系统会在内存查找可用的页面,如果找到的页面已经被修改过,那么系统还必须将它们换出到页交换文件中。

Windows还提供了一种特性,一路使得应用程序能够提高中自身的性能-----这项特性就是重置物理存储器。重置物理存储器的意思是,我们告诉系统一个或几个物理存储页中的数据没有被修改过。如果系统正在查找一页闲置内存并且找到了一个修改过的页面,那么系统必须把该内存写入到页交换文件中。这个操作比较慢,会影响性能。对大多数应用程序来说,我们都希望系统把修改后的页面保存到页交换文件中。

但是,有些应用程序只需要在一小段时间内使用存储器,之后也不需要保留存储器中的内容。为了提高性能,应用程序可以告诉系统不要在页交换文件中保存指定存储器。这基本上是应用程序用来告诉系统一个页面未被修改过的一种方法。因此,如果系统决定将一个内存页挪作他用,好么它不会将页面内容保存到页交换文件中,这样提高了性能。为了重置存储器,应用程序应该调用VirtualAlloc函数,并在第三个参数中传MEM_RESET标志。

15.8 地址窗口扩展

地址窗口扩展特性:

1.允许应用程序以一种特殊的方式分配内存,操作系统保证不会将以这种方式分配的内存换出到磁盘上

2.允许应用程序访问比进程地址空间还要多的内存。

基本上 AWE提供了一种方式,可以让应用程序分配一块或多块内存。当一开始分配时,在进程的地址空间中是看不见这些内存块的应用程序然后预订地址空间区域,这就是地址窗口。应用程序然后调用一个函数,每调用一次把一块内存指定到该地址窗口。把内存块指定到地址窗口是非常快的。

复制代码
//1.预订1MB地址空间
    ULONG_PTR ulRAMBytes = 1024 * 1024;
    PVOID pvWindow = VirtualAlloc(NULL,ulRAMBytes,
        MEM_RESERVE | MEM_PHYSICAL ,PAGE_READWRITE);

    //2.得到当前平台的一个页面的大小
    SYSTEM_INFO sinf;
    GetSystemInfo(&sinf);

    //3.计算需要多少内存页
    ULONG_PTR ulRAMPages = (ulRAMBytes + sinf.dwPageSize - 1) / sinf.dwPageSize;

    //4.分配内存页数组、
    ULONG_PTR * aRAMPages = (ULONG_PTR * ) new ULONG_PTR[ulRAMPages];

    //5.分配物理存储器
    AllocateUserPhysicalPages(GetCurrentProcess(),
        &ulRAMPages,
        aRAMPages);

    //6. 指定内存块指定给地址窗口 
    MapUserPhysicalPages(pvWindow,
        ulRAMPages,
        aRAMPages);

    //7.使用内存...

    //8.释放内存页块
    FreeUserPhysicalPages(GetCurrentProcess(),
        &ulRAMPages,
        aRAMPages);

    VirtualFree(pvWindow,0,MEM_RELEASE);
    delete [] aRAMPages;
复制代码
相关文章
|
2天前
|
Windows
LabVIEW启用/禁用Windows屏幕保护程序
LabVIEW启用/禁用Windows屏幕保护程序
13 4
LabVIEW启用/禁用Windows屏幕保护程序
|
3天前
|
编解码 Windows
LabVIEW应用程序在Windows版本之间的字体变化
LabVIEW应用程序在Windows版本之间的字体变化
|
4天前
|
消息中间件 监控 NoSQL
中间件应用合理配置内存
中间件应用合理配置内存
11 2
|
5天前
|
安全 Java Android开发
构建高效Android应用:采用Kotlin进行内存优化的策略
【5月更文挑战第8天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,合理管理内存资源是确保应用流畅运行的关键因素之一。近年来,Kotlin作为官方推荐的开发语言,以其简洁、安全和互操作性的特点受到开发者青睐。本文将深入探讨利用Kotlin语言特性,通过具体策略对Android应用的内存使用进行优化,旨在帮助开发者提高应用性能,减少内存消耗,避免常见的内存泄漏问题。
8 0
|
6天前
|
存储 安全 搜索推荐
Windows之隐藏特殊文件夹(自定义快捷桌面程序)
Windows之隐藏特殊文件夹(自定义快捷桌面程序)
|
11天前
|
Windows
Windows 程序自启动实现方法详解
Windows 程序自启动实现方法详解
26 0
|
12天前
|
缓存 安全 Android开发
构建高效Android应用:采用Kotlin进行内存优化
【5月更文挑战第1天】随着移动设备的普及,用户对应用程序的性能要求越来越高。特别是对于Android开发者来说,理解并优化应用的内存使用是提升性能的关键。本文将探讨使用Kotlin语言在Android开发中实现内存优化的策略和技术。我们将深入分析Kotlin特有的语言特性和工具,以及它们如何帮助开发者减少内存消耗,避免常见的内存泄漏问题,并提高整体应用性能。
|
12天前
|
机器学习/深度学习 自动驾驶 安全
深入理解操作系统内存管理:策略与实现基于深度学习的图像识别技术在自动驾驶系统中的应用
【4月更文挑战第30天】 在现代计算机系统中,操作系统的内存管理是确保系统高效、稳定运行的关键组成部分。本文将深入探讨操作系统中内存管理的多种策略及其实现机制,包括但不限于分页、分段和段页式结合等技术。我们将剖析内存分配的原理,讨论虚拟内存技术的实现以及它如何提供更大的地址空间并允许内存的交换。同时,我们还会涉及内存保护机制,它们是如何防止程序访问未授权的内存区域。最后,文中将对现代操作系统如Linux和Windows中的内存管理实践进行比较分析,以期给读者提供全面而深入的理解和参考。 【4月更文挑战第30天】 随着人工智能技术的飞速发展,深度学习已经
|
12天前
|
安全 网络安全 Android开发
云端防御策略:融合云服务与网络安全的未来构建高效的Android应用:从内存优化到电池寿命
【4月更文挑战第30天】 随着企业加速向云计算环境转移,数据和服务的云端托管成为常态。本文探讨了在动态且复杂的云服务场景下,如何构建和实施有效的网络安全措施来保障信息资产的安全。我们将分析云计算中存在的安全挑战,并展示通过多层次、多维度的安全框架来提升整体防护能力的方法。重点关注包括数据加密、身份认证、访问控制以及威胁检测与响应等关键技术的实践应用,旨在为读者提供一种结合最新技术进展的网络安全策略视角。 【4月更文挑战第30天】 在竞争激烈的移动市场中,Android应用的性能和资源管理已成为区分优秀与平庸的关键因素。本文深入探讨了提升Android应用效率的多个方面,包括内存优化策略、电池
|
13天前
|
算法 安全 Android开发
深入理解操作系统的内存管理机制构建高效Android应用:Kotlin的协程优势
【4月更文挑战第30天】 在现代计算机系统中,操作系统的内存管理是确保系统高效、稳定运行的关键。本文将探讨操作系统内存管理的核心技术,包括内存分配、虚拟内存、分页和分段等概念,以及它们是如何协同工作以提高内存利用率和系统性能的。通过对这些技术的详细分析,我们可以更好地理解操作系统背后的原理,并评估不同内存管理策略对系统行为的影响。 【4月更文挑战第30天】 在移动开发领域,尤其是针对Android平台,性能优化和流畅的用户体验始终是开发者追求的核心目标。随着Kotlin语言的普及,协程作为其在异步编程领域的杀手锏特性,已经逐渐成为提高应用性能和简化代码结构的重要工具。本文将深入探讨Kotli

相关课程

更多