文档章节

内存管理[3]

涂孟超
 涂孟超
发布于 2014/09/26 15:36
字数 1238
阅读 6
收藏 0
VirtualAlloc 分配的内存是以 4K 为最小单位、连续的内存地址(但映射到真实的内存时它不一定是连续的), 前面说了, 它不适合分配小内存(譬如只有几个字节的变量); 局部的变量在 "栈" 中有程序自动管理, 那么那些全局的小变量怎么办呢? 这就要用到 "堆".

这样看来, VirtualAlloc 分配的内存既不是 "栈" 也不是 "堆"; VirtualAlloc 分配的内存地址是连续的, "堆" 中内容一般是不连续的, 所以管理 "堆" 比较麻烦, 它是通过双线链表的结构方式管理的; 程序可以拥有若干个 "堆", 每一个 "堆" 都会有一个句柄, 访问 "堆" 中的内容时先要找到这个 "堆", 然后再遍历链表, 这可能就是 "堆" 比 "栈" 慢的根本原因.

在 "堆" 中分配内存(HeapAlloc)前先要建立 "堆"(HeapCreate), 就像程序有默认的 "栈" 一样, 每一个程序都有一个默认建立的 "堆"(可以用 GetProcessHeap 获取这个 "默认堆" 的句柄), 我们在 Delphi 中用到 "堆" 时, 使用的就是这个 "默认堆". 如果让程序更灵活地拥有多个 "堆", 必须要用到 API 函数.

建立 "堆" 时会同时提交真实内存的, 这在申请大内存时会很慢, 所以默认堆也只有 1M, 但 "默认堆" 并没有限制大小, 它会根据需要动态增长.

有了 "默认堆" 还有必要申请其他的 "堆" 吗? 这只有在多线程中才能体现出来, 和 "栈" 不一样, 程序会给每个线程分配一个 "栈区"; 而 "默认堆" 是进程中的所有线程公用的, 当一个线程使用 "默认堆" 时, 另一个需要使用 "堆" 的线程就要先挂起等待, 也就是它们不能同时使用; 只有通过 API 函数重新建立的私有堆才是互不干涉、最有效率的.

先了解一下 "堆" 相关的函数.
//建立堆; 注意建立时指定的尺寸也是按页大小(PageSize)对齐的, 譬如指定 15k, 实际会分配 16K.
HeapCreate(
  flOptions: DWORD;     {堆属性选项, 见下表}
  dwInitialSize: DWORD; {初始尺寸, 单位是字节; 该大小会被直接提交到实际的内存}
  dwMaximumSize: DWORD  {最大尺寸, 如果不限定最大值就设为 0}
): THandle;             {返回堆句柄; 失败返回 0, 但如果参数 flOptions 允许了异常, 失败会返回异常标识}

//flOptions 参数可选值:
HEAP_NO_SERIALIZE        = 1; {非互斥, 此标记可允许多个线程同时访问此堆}
HEAP_GENERATE_EXCEPTIONS = 4; {当建立堆出错时, 此标记可激发一个异常并返回异常标识}
HEAP_ZERO_MEMORY         = 8; {把分配的内存初始化为 0}

//flOptions 参数指定有 HEAP_GENERATE_EXCEPTIONS 时, 可能返回的异常:
STATUS_ACCESS_VIOLATION = DWORD($C0000005); {参数错误}
STATUS_NO_MEMORY        = DWORD($C0000017); {内存不足}

 
 
 
 
 

 

 

  
//销毁堆 HeapDestroy( hHeap: THandle {堆句柄} ): BOOL; {}
//从堆中申请内存 HeapAlloc( hHeap: THandle; {堆句柄} dwFlags: DWORD; {内存属性选项, 见下表} dwBytes: DWORD {申请内存的大小, 单位是字节} ): Pointer; {返回内存指针; 失败返回 0 或异常, 情况和建立堆是一样} //dwFlags 参数可选值: HEAP_NO_SERIALIZE = 1; {非互斥, 此标记可允许多个线程同时访问此堆} HEAP_GENERATE_EXCEPTIONS = 4; {当建立堆出错时, 此标记可激发一个异常并返回异常标识} HEAP_ZERO_MEMORY = 8; {把分配的内存初始化为 0} {能看出这和堆的属性选项是一样的; 如果 dwFlags 参数设为 0, 将使用堆的属性; 如果重新指定将覆盖堆的属性} {另外: 如果堆是默认堆, 也就是堆句柄来自 GetProcessHeap, dwFlags 参数会被忽略}
//改变堆内存的大小, 也就是重新分配 HeapReAlloc( hHeap: THandle; {句柄} dwFlags: DWORD; {内存属性选项; 该参数比 HeapAlloc 多出一个选项, 见下表} lpMem: Pointer; {原内存指针} dwBytes: DWORD {新的尺寸} ): Pointer; {同 HeapAlloc} //dwFlags 参数可选值: HEAP_NO_SERIALIZE = 1; {非互斥, 此标记可允许多个线程同时访问此堆} HEAP_GENERATE_EXCEPTIONS = 4; {当建立堆出错时, 此标记可激发一个异常并返回异常标识} HEAP_ZERO_MEMORY = 8; {把分配的内存初始化为 0} HEAP_REALLOC_IN_PLACE_ONLY = 16; {此标记不允许改变原来的内存位置}
//获取堆中某块内存的大小 HeapSize( hHeap: THandle; {堆句柄} dwFlags: DWORD; {内存属性; 可选值是 0 或 HEAP_NO_SERIALIZE, 后者可确保同步访问} lpMem: Pointer {内存指针} ): DWORD; {成功返回字节为单位的大小; 失败返回 $FFFFFFFF}
//释放堆中指定的内存块 HeapFree( hHeap: THandle; {堆句柄} dwFlags: DWORD; {内存属性; 可选值是 0 或 HEAP_NO_SERIALIZE} lpMem: Pointer {内存指针} ): BOOL; {}
//验证堆 HeapValidate( hHeap: THandle; {} dwFlags: DWORD; {} lpMem: Pointer {} ): BOOL; {}
//整理堆 HeapCompact( hHeap: THandle; {} dwFlags: DWORD {} ): UINT; {}
//锁定堆 HeapLock( hHeap: THandle {} ): BOOL; {}
//锁定后的解锁 HeapUnlock( hHeap: THandle {} ): BOOL; {}
//列举堆中的内存块 HeapWalk( hHeap: THandle; {} var lpEntry: TProcessHeapEntry {} ): BOOL; {}
举例放下篇吧.

本文转载自:http://www.cnblogs.com/del/archive/2008/05/08/1188715.html

共有 人打赏支持
涂孟超
粉丝 12
博文 2011
码字总数 14107
作品 0
深圳
程序员
Memcached与Redis(三)

3. Memcached和Redis关键技术对比 作为内存数据缓冲系统,Memcached和Redis均具有很高的性能,但是两者在关键实现技术上具有很大差异,这种差异决定了两者具有不同的特点和不同的适用条件。下...

liujing07
06/26
0
0
iOS中的内存管理(上)

下列行为都会增加一个app的内存占用: 1、创建一个OC对象; 2、定义一个变量; 3、调用一个函数或者方法。 如果app占用内存过大,系统可能会强制关闭app,造成闪退现象,影响用户体验。如何让...

傲风凌寒
2014/05/20
0
0
OC内存管理常见的面试题

#####面试:说一说对内存管理的理解?(原理) - 手动内存管理(MRC):1.在创建一个对象的时候系统会自动创建这个对象的引用计数并赋值为1;2.当引用计数为0的时候,对象会去调用dealloc方法来...

鹿微微鹿
2016/03/25
275
0
tcmalloc jemalloc glibc内存分配管理模块性能测试对比

tcmalloc是谷歌提供的内存分配管理模块 jemalloc是FreeBSD提供的内存分配管理模块 glibc是Linux提供的内存分配管理模块 并发16个线程,分配压测3次,每次压15分钟,可以看到谷歌的tcmalloc内...

技术小甜
2017/11/08
0
0
深入理解Linux内存管理-之-目录导航

转自:https://blog.csdn.net/gatieme/article/details/52384965 1 内存描述 2 页表管理 3 初始化内存管理

zwfgogo
04/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

OSChina 周三乱弹 —— 公司女同事约我

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子:分享水木年华的单曲《蝴蝶花(2002年大提琴版)》 《蝴蝶花(2002年大提琴版)》- 水木年华 手机党少年们想听歌,请使劲儿戳(这里) ...

小小编辑
5分钟前
12
3
Linux环境搭建 | VMware下共享文件夹的实现

在进行程序开发的过程中,我们经常要在主机与虚拟机之间传递文件,比如说,源代码位于虚拟机,而在主机下阅读或修改源代码,这里就需要使用到 「共享文件」 这个机制了。本文介绍了两种共享文...

良许Linux
今天
5
0
JUC锁框架——AQS源码分析

JUC锁介绍 Java的并发框架JUC(java.util.concurrent)中锁是最重要的一个工具。因为锁,才能实现正确的并发访问。而AbstractQueuedSynchronizer(AQS)是一个用来构建锁和同步器的框架,使用A...

长头发-dawn
今天
3
0
docker中安装了RabbitMQ后无法访问其Web管理页面

在官网找了"$ docker run -d --hostname my-rabbit --name some-rabbit -p 8080:15672 rabbitmq:3-management"这条安装命令,在docker上安装了RabbitMQ,,结果输入http://localhost:8080并不......

钟然千落
今天
4
1
spring-cloud | 分布式session共享

写在前面的话 各位小伙伴,你们有福了,这一节不仅教大家怎么实现分布式session的问题,还用kotlin开发,喜欢kotlin的小伙伴是不是很开心! 以前在写Android的时候,就对客户端请求有一定的认...

冯文议
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部