part 10.1 - 内存管理

part 10.1 - 内存管理

标签(空格分隔): win32汇编


内存管理


1)内存管理基础

  1. windows内存管理的层次:
    • 标准内存管理函数:在默认堆中分配和释放内存,常规意义上的内存管理函数。
    • 堆管理函数:有效地故案例内存和进程的地址空间。(堆:程序初始化时向操作系统申请并预留的大内存快)
    • 虚拟内存管理函数:保留/提交/释放虚拟内存,在虚拟内存页上改变保护位,锁定虚拟内存页
    • 内存映射文件函数:将文件直接映射到进程的地址空间中。
  2. 堆:

    • win32中分两种堆:默认堆、私有堆
    • 默认堆:一个进程只有一个,线程共享。
    • 私有堆:一个进程可有多个,线程独占。

    win16中内存有“全局”和“本地”之分;
    全局堆(Gloabl Heap)是系统中所有进程所共有的堆,每个进程有一个私有的本地堆(Local Heap)
    Win32下,考虑到安全,所有进程使用的全局堆废除,本地堆改名为进程堆(Process Heap)即默认堆。

  3. 内存的状态

    • 一个进程地寻址空间为4GB
    • 高端2GB共操作系统内核使用。
    • 低端2GB应用程序使用。

      • 该2GB包括应用程序、用户DLL代码、静态数据段。
      • 剩余的空间才是内存函数可使用的地址空间。

      PS:可分配内存的大小还受制于物理内存和物理交换文件的大小。
      GlobalMemeoryStatus 可以获取内存信息。

  4. windows可以根据内存使用的需求自动调整交换文件的大小。


2)标准内存管理函数

  • 标准内存管理函数的功能是在进程的默认堆中申请和释放内存块。
  • 函数组成

    函数名作用参数返回值
    GlobalAlloc*申请固定的内存块Flag : 标志
    dwBytes:内存大小
    成功: 地址 or 句柄
    失败: NULL
    GlobalReAlloc*修改内存块大小lpMemory:内存指针
    dwBytes:新的大小
    uFlags:是否允许移动
    成功:新的指针
    失败:NULL
    GlobalFree释放固定内存块lpMemory or hMemory成功 :NULL /失败:lpMemory
    GlobalLock内存上锁hMemory返回举兵指针
    GlobalUnlock内存解锁hMemory成功:非0值
    GlobalDiscard当可丢弃内存块的锁定计数为0时,
    可使用该函数丢弃
    hMemory
    GlobalFlags333
    GlobalHandle444
    GlobalSize555
  • GlobalAlloc Flag参数
    • GMEM_FIXED:申请固定内存块
    • GMEM_ZERO:初始化为0
    • GMEM_MOVEABLE:可移动内存块 - 操作系统根据内存情况移动内存块,以防止碎片,
      此时成功时返回的是内存句柄而不是指针
    • GMEM_DISCARDBAABLE:windows急需内存时可以将他从物理内存中丢弃。
      当对他使用GlobalLock返回NULL时,说明已经被Windows丢弃。
  • GlbalReAlloc-uFlag
    • GMEM_MOVEABLE:必要的时候可移动
    • GlobalLock(UnLock):维护一计数器,lock+1,Unlock-1,计数器为0时才真正解锁。

3)堆管理函数

  • 堆管理函数:私有堆相当于在默认堆中保留了一大块内存,使用堆管理函数可以在这个保留的内存块中分配内存。
  • 同步问题:
    • 默认堆的访问时顺序进行的。(线程间同步)
    • 私有堆空间线程独占
    • 申请私有堆的过程是独占的,使用默认参数申请时,系统会进行独占检测
  • 从默认堆申请私有堆时操作系统的执行过程:

    1. 遍历已分配的和空闲的内存块的链接表 ——-(什么玩意
    2. 寻找一个空闲内存块地址
    3. 通过将空闲内存快标记为”已分配”来分配新的内存块。(临界区)
    4. 将新内存块添加给内存块链接表。(临界区)
      PS:步骤3、4是临界区。系统会进行独占的检测工作。
  • 函数组成

    函数名作用返回值
    HeapCreate创建私有堆成功:返回内存地址
    失败:NULL or 出错代码
    HeapDestory释放私有堆所有内存快或
    返回堆占用的物理内存和保留的地址空间返回系统
    成功: TRUE
    失败
    HeapAlloc在堆中分配或释放内存块成功:内存块指针
    失败:NULL或错误代码
    HeapFree释放分配的内存块成功: 非0值<失败>NULL 或 错误代码
    HeapReAlloc重新调整大小成功:返回新内存块指针
    GetProcessHeap获取默认堆的堆句柄默认堆句柄
    GetProcessHeaps列出进程中所有的堆成功:参数lpHeaps获取接受堆句柄的缓冲区,包括默认堆
    HeapWalk遍历堆栈lpEntry获取包含内存块信息的PROCESS_HEAP_ENTRY结构,
    若还有堆则返回true否侧flase
    多线程编程中必须使用Heaolock
    • 其他函数:

      1. HeapValidate:验证堆的完整性
      2. HeapLock、HeapUnlock:锁定堆、解锁堆,某线程锁定堆后即成为该堆所有者,
        其他线程访问该堆将被阻塞
      3. HeapCompact:合并队中的空闲内存快,释放不在使用中的内存页面
      4. HeapSize:返回堆中某个内存块的大小
    • HeapCreate中的flOptions参数

      1. HEAP_NO_SERIALIZE:不进行独占检测(祥见P339)

      由上知,建立私有堆,操作系统会进行独占检测,但是也存在不需要独占 检测的情况
      1. 进程只使用一个线程
      2. 进程使用多个线程,但每个线程之访问属于自己的私有堆
      3. 进程使用多个线程,但程序中已经有其他措施来保证他们不会同时取访问同一个私有堆

    • HEAP_GENERATE_EXCEPTIONS:函数失败时返回错误代码
      PS: 错误代码必然大于0c0000000h,此后是系统空间,不会和成功的情况冲突。
  • HeapDistory可以用来释放私有堆,同时也可以释放默认堆,
    默认堆的句柄可以通过GetProcessHeap获得

  • HeapReAlloc 中的dwFlags参数:
    若指定 HEAP_REALLOC_IN_PLACE_ONLY则函数会在需要的时候自动移动内存块

4)虚拟内存管理函数

  • 程序运行时,进程的每个地址每个都可能处于三种状态中的一种
    1. 占用状态:线程地址已经映射到实际的物理内存中(已提交状态)
    2. 自由状态:没有映射到物理内存中,线程地址当前也没有被程序使用
    3. 保留状态:线程地址没有映射到物理内存中,但他不会被使用,知道程序希望使用它位止
      任何自由状态的地址在能够被使用前首先被分配位保留或已提交状态。
  • 虚拟内存管理函数的功能
    • 使用虚拟内存管理函数可指定内存块位于那个线程地址。
    • 将内存的状态从提交变为保留
    • 将保护模时从PAGE_READWRITE改为PAGE_READONLY
    • 锁定一页内存
  • 函数组成

    1. VirtualAlloc 、 VirtualFree:地址空间的分配和释放

    1. VirtualAlloc可以指定一个地址来保留或提交,保留只是组织其他内存分配函数对该段地址的请求
    2. VirtualAlloc保留一段地址之后,再多次调用以提交该地址空间的不同页面,故该段地址空间的不同页面可能处于不同状态,而调用VirtualFree要求该地址空间状态相同。
    3. VirtualAlloc提交时,操作系统根据制定内存块,将制定内存块涉及的页面全部提交(制定内存块不一定是整页面),返回有所偏移的地址
  • VirtualLock、VirtualUnlock :内存页进行锁定和解锁

  • VirtualQuery、VirtualQueryEx:查询内存页状态
  • VirtualProtect、VirtualProtectEx:改变内存页的保护属性

    假设一个进程要处理一个大小变化的数据流,当CPU忙时,分到的时间片可能无法解决太大的数据,可以使用该函数位一块内存的顶端页设置PAGE_NOACCESS保护位,任何想要访问该内存的请求都会发生一个异常,通过捕获该一场就可以来做出相应对策

  • RtlMoveMemory:移动内存
  • RtlFillMomory:以dbFill参数填充内存块
  • RtlZeroMomory:以0填充内存块
  • IsBadCodePtr:测试某个指针指向的单个字节是否可读
  • IsBadReadPtr:测试某段内存是否可读
  • IsBadWritePtr:测试某段内存是否可写
  • IsBadStringPtr:测时一个null-terminated String 是否可读
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值