内存管理三

news/2024/7/20 15:59:32 标签: 内存管理, 数据结构与算法

VirtualAlloc 分配的内存是以 4K 为最小单位、连续的内存地址(但映射到真实的内存时它不一定是连续的), 前面说了, 它不适合分配小内存(譬如只有几个字节的变量); 局部的变量在 "栈" 中有程序自动管理, 那么那些全局的小变量怎么办呢? 这就要用到 "堆".
9 q% /+ Q1 L, }1 F2 x$ D5 D! A
+ n! q4 O% a  Q5 x0 r3 Y这样看来, VirtualAlloc 分配的内存既不是 "栈" 也不是 "堆"; VirtualAlloc 分配的内存地址是连续的, "堆" 中内容一般是不连续的, 所以管理 "堆" 比较麻烦, 它是通过双线链表的结构方式管理的; 程序可以拥有若干个 "堆", 每一个 "堆" 都会有一个句柄, 访问 "堆" 中的内容时先要找到这个 "堆", 然后再遍历链表, 这可能就是 "堆" 比 "栈" 慢的根本原因.
% T: Q5 B1 i+ [/ e9 r' K# F--------------------------------------------------------------------------------2 p9 D6 w; y( h$ L0 m7 O, p
0 g$ j% {! l+ M  K8 I/ c
在 "堆" 中分配内存(HeapAlloc)前先要建立 "堆"(HeapCreate), 就像程序有默认的 "栈" 一样, 每一个程序都有一个默认建立的 "堆"(可以用 GetProcessHeap 获取这个 "默认堆" 的句柄), 我们在 Delphi 中用到 "堆" 时, 使用的就是这个 "默认堆". 如果让程序更灵活地拥有多个 "堆", 必须要用到 API 函数.5 J0 g% Y9 L4 k0 Q

, T. P  l1 g& D( e建立 "堆" 时会同时提交真实内存的, 这在申请大内存时会很慢, 所以默认堆也只有 1M, 但 "默认堆" 并没有限制大小, 它会根据需要动态增长.* L- e: ]8 k( e1 K# F

! I+ M; g* v4 S; /; o) X' T有了 "默认堆" 还有必要申请其他的 "堆" 吗? 这只有在多线程中才能体现出来, 和 "栈" 不一样, 程序会给每个线程分配一个 "栈区"; 而 "默认堆" 是进程中的所有线程公用的, 当一个线程使用 "默认堆" 时, 另一个需要使用 "堆" 的线程就要先挂起等待, 也就是它们不能同时使用; 只有通过 API 函数重新建立的私有堆才是互不干涉、最有效率的.5 C" O3 z( E4 r8 u" R& t0 ?
--------------------------------------------------------------------------------; k0 W4 [' r# f1 w& r2 A1 b, A

+ o5 R& A! L. D4 d; d3 _先了解一下 "堆" 相关的函数.) B' j2 a* m( D% K% C) I; M7 g
--------------------------------------------------------------------------------

  1. //建立堆; 注意建立时指定的尺寸也是按页大小(PageSize)对齐的, 譬如指定 15k, 实际会分配 16K.
  2. HeapCreate(
  3.   flOptions: DWORD;     {堆属性选项, 见下表}
  4.   dwInitialSize: DWORD; {初始尺寸, 单位是字节; 该大小会被直接提交到实际的内存}
  5.   dwMaximumSize: DWORD  {最大尺寸, 如果不限定最大值就设为 0}
  6. ): THandle;             {返回堆句柄; 失败返回 0, 但如果参数 flOptions 允许了异常, 失败会返回异常标识}
  7. //flOptions 参数可选值:
  8. HEAP_NO_SERIALIZE        = 1; {非互斥, 此标记可允许多个线程同时访问此堆}
  9. HEAP_GENERATE_EXCEPTIONS = 4; {当建立堆出错时, 此标记可激发一个异常并返回异常标识}
  10. HEAP_ZERO_MEMORY         = 8; {把分配的内存初始化为 0}
  11. //flOptions 参数指定有 HEAP_GENERATE_EXCEPTIONS 时, 可能返回的异常:
  12. STATUS_ACCESS_VIOLATION = DWORD($C0000005); {参数错误}
  13. STATUS_NO_MEMORY        = DWORD($C0000017); {内存不足}
复制代码

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

  1. //销毁堆
  2. HeapDestroy(
  3. hHeap: THandle {堆句柄}
  4. ): BOOL;       {}
复制代码

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

  1. //从堆中申请内存
  2. HeapAlloc(
  3.   hHeap: THandle; {堆句柄}
  4.   dwFlags: DWORD; {内存属性选项, 见下表}
  5.   dwBytes: DWORD  {申请内存的大小, 单位是字节}
  6. ): Pointer;       {返回内存指针; 失败返回 0 或异常, 情况和建立堆是一样}
  7. //dwFlags 参数可选值:
  8. HEAP_NO_SERIALIZE        = 1; {非互斥, 此标记可允许多个线程同时访问此堆}
  9. HEAP_GENERATE_EXCEPTIONS = 4; {当建立堆出错时, 此标记可激发一个异常并返回异常标识}
  10. HEAP_ZERO_MEMORY         = 8; {把分配的内存初始化为 0}
  11. {能看出这和堆的属性选项是一样的; 如果 dwFlags 参数设为 0, 将使用堆的属性; 如果重新指定将覆盖堆的属性}
  12. {另外: 如果堆是默认堆, 也就是堆句柄来自 GetProcessHeap, dwFlags 参数会被忽略}
复制代码

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

  1. //改变堆内存的大小, 也就是重新分配
  2. HeapReAlloc(
  3.   hHeap: THandle; {句柄}
  4.   dwFlags: DWORD; {内存属性选项; 该参数比 HeapAlloc 多出一个选项, 见下表}
  5.   lpMem: Pointer; {原内存指针}
  6.   dwBytes: DWORD  {新的尺寸}
  7. ): Pointer;       {同 HeapAlloc}
  8. //dwFlags 参数可选值:
  9. HEAP_NO_SERIALIZE          = 1;  {非互斥, 此标记可允许多个线程同时访问此堆}
  10. HEAP_GENERATE_EXCEPTIONS   = 4;  {当建立堆出错时, 此标记可激发一个异常并返回异常标识}
  11. HEAP_ZERO_MEMORY           = 8;  {把分配的内存初始化为 0}
  12. HEAP_REALLOC_IN_PLACE_ONLY = 16; {此标记不允许改变原来的内存位置}
复制代码

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

  1. //获取堆中某块内存的大小
  2. HeapSize(
  3.   hHeap: THandle; {堆句柄}
  4.   dwFlags: DWORD; {内存属性; 可选值是 0 或 HEAP_NO_SERIALIZE, 后者可确保同步访问}
  5.   lpMem: Pointer  {内存指针}
  6. ): DWORD;         {成功返回字节为单位的大小; 失败返回 $FFFFFFFF}
复制代码

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

  1. //释放堆中指定的内存块
  2. HeapFree(
  3.   hHeap: THandle; {堆句柄}
  4.   dwFlags: DWORD; {内存属性; 可选值是 0 或 HEAP_NO_SERIALIZE}
  5.   lpMem: Pointer  {内存指针}
  6. ): BOOL;          {}
复制代码

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

  1. //验证堆
  2. HeapValidate(
  3.   hHeap: THandle; {}
  4.   dwFlags: DWORD; {}
  5.   lpMem: Pointer  {}
  6. ): BOOL;          {}
复制代码

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

  1. //整理堆
  2. HeapCompact(
  3.   hHeap: THandle; {}
  4.   dwFlags: DWORD  {}
  5. ): UINT;          {}
复制代码

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

  1. //锁定堆
  2. HeapLock(
  3.   hHeap: THandle {}
  4. ): BOOL;         {}
复制代码

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

  1. //锁定后的解锁
  2. HeapUnlock(
  3.   hHeap: THandle {}
  4. ): BOOL;         {}
复制代码

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

  1. //列举堆中的内存块
  2. HeapWalk(
  3.   hHeap: THandle;                {}
  4.   var lpEntry: TProcessHeapEntry {}
  5. ): BOOL;                         {}

转载于:https://www.cnblogs.com/hnxxcxg/archive/2010/06/17/2940694.html


http://www.niftyadmin.cn/n/793670.html

相关文章

服务器切换文档,服务器切换文档

服务器切换文档 内容精选换一换华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。用户在创建云服务器或为云服务器切换操作系统时,有时会…

动态服务器页面asp代码文件路径,Image显示服务器上任意绝对路径下的图片(采用二进制流实现)...

我要实现这样一个需求:数据库中存储的是照片所在的绝对路径(可以不在系统所在路径下),Image控件动态加载路径下的图片。看到这个题目,有些人会说,这还不简单啊,将URL直接设置成绝对路径不就行了啊。我只能说&#xff0…

fs2410开发板搭建网站服务器,学习 ARM 系列 -- FS2410 开发板上 Nand Flash 到内存的代码搬移...

一、目的前面做过一个实验,搬移 Nand Flash 里的前 4k 代码到内存指定位置,这其实是把SRAM 从 0x40000000 开始的 4K 代码复制到 SDRAM 的指定位置,并没有涉及到对 NandFlash 的操作。究其原因,开发板上电后,Nand Flas…

python中的django库遇到打不开manage.py的问题

python: cant open file manage.py: [Errno 2] No such file or directory1、小白入门django遇到的小问题2、django 开发为什么需要虚拟环境3、安装虚拟环境4、创建虚拟环境1、小白入门django遇到的小问题 当你入门Django时,想要启动服务时,报的错误是这…

Android小白看过来,跟我一起学Android之真机调试环境搭建

真机调试环境搭建将测试机和开发机通过USB连接通过命令查看USB连接情况:lsusb查找你的手机所连接端口的ID: ID 17ef创建Android真机的USB规则: gedit /etc/udev/rules.d/android.rules //注意权限 #SomeDeice 17ef SUBSYSTEM"usb"…

Android基础知识,查漏补缺(一)

Android基础知识,查漏补缺查漏补缺第一课1、什么是JDK?2、Android系统架构概览3、Intent-filter是干啥的4、AndroidManifest.xml分析5、”value”子目录6、Fragment6.1、谈一谈Fragment的生命周期6.2、谈一谈Fragment和Activity的区别?6.3、F…

2D图形应用的场景

Android基础知识之2D图形1、2D图形应用的场景2、Graphics 概述2.1、Paint类2.2、Color类2.3、Canvas(画布)2.4、Canvas绘制几何图形2.5、Canvas绘制字符串2.6、绘制图像2.7、图像缩放旋转处理2.8、图像像素操作实现特效2.9、获得屏幕分辨率3、Animation概述3.1、Tween动画3.2、…

Android基础知识之多线程

Android基础知识之多线程1、为什么使用多线程2、多线程的实现方法3、线程间通信4、 线程安全1、为什么使用多线程 防止ANR 什么是ANR(Application Not Responding)主线程阻塞Activity的最长执行时间是5秒BroadcastReceiver的最长执行时间是10秒Activity Manager/Window Mangage…