`
bbls
  • 浏览: 61583 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类

内存堆栈

阅读更多

对内存进 行操作的第三个机制是使用堆栈。堆栈可以用来分配许多较小的数据块。例如,若要对链接表和链接树进行管理,最好的方法是使用堆栈,堆栈的优点是,可以不考 虑分配粒度和页面边界之类的问题,集中精力处理手头的任务。堆栈的缺点是,分配和释放内存块的速度比其他机制要慢,并且无法直接控制物理存储器的提交和回 收。
从内部来讲,堆栈是保留的地址空间的一个区域。开始时,保留区域中的大多数页面没有被 提交物理存储器。当从堆栈中进行越来越多的内存分配时,堆栈管理器将把更多的物理存储器提交给堆栈。物理存储器总是从系统的页文件中分配的,当释放堆栈中 的内存块时,堆栈管理器将收回这些物理存储器。

线程的堆栈:

每当创建一个线程时,系统就会为线程的堆栈(每个线程有它自己的堆栈) 保留一个堆栈空间区域,并将一些物理存储器提交给这个已保留的区域。按照默认设置,系统保留1 MB的地址空间并提交两个页面的内存。但是,这些默认值是可以修改的,方法是在你链接应用程序时设定M i c r o s o f t的链接程序的/ S TA C K选项:

/STACK:reserve[,commit]









当创建一个线程的堆栈时,系统将会保留一个链接程序的/ S TA C K开关指明的地址空间区域。
进程的默认堆栈

当进程初始化时,系统在进程的地址空间中创建一个堆栈。该堆栈称为进程的默认堆栈。按照默认设置, 该堆栈的地址空间区域的大小是1 MB。但是,系统可以扩大进程的默认堆栈,使它大于其默认值。当创建应用程序时,可以使用/ H E A P链接开关,改变堆栈的1 M B默认区域大小。由于D L L没有与其相关的堆栈,所以当链接D L L时,不应该使用/ H E A P链接开关。/ H E A P链接开关的句法如下:

/HEAP:reserve[,commit]









许多Wi n d o w s函数要求进程使用其默认堆栈。特别是widows提供的API。对默认堆栈的访问是顺序进行的。换句话说,系统必须保证在规定的时间内,每次只有一个线 程能够分配和释放默认堆栈中的内存块。如果两个线程试图同时分配默认堆栈中的内存块,那么只有一个线程能够分配内存块,另一个线程必须等待第一个线程的内 存块分配之后,才能分配它的内存块。一旦第一个线程的内存块分配完,堆栈函数将允许第二个线程分配内存块。这种顺序访问方法对速度有一定的影响。如果你的 应用程序只有一个线程,并且你想要以最快的速度访问堆栈,那么应该创建你自己的独立的堆栈,不要使用进程的默认堆栈。

单个进程可以同时拥有若干个堆栈。这些堆栈可以在进程的寿命期中创建和撤消。但是,默认堆栈是在进 程开始执行之前创建的,并且在进程终止运行时自动被撤消。不能撤消进程的默认堆栈。每个堆栈均用它自己的堆栈句柄来标识,用于分配和释放堆栈中的内存块的 所有堆栈函数都需要这个堆栈句柄作为其参数。

可以通过调用G e t P r o c e s s H e a p函数获取你的进程默认堆栈的句柄:

HANDLE GetProcessHeap();









为什么要创建辅助堆栈

除了进程的默认堆栈外,可以在进程的地址空间中创建一些辅助堆栈。由于下列原因,你可能想要在自己 的应用程序中创建一些辅助堆栈:

• 保护组件。

• 更加有效地进行内存管理。

• 进行本地访问。

• 减少线程同步的开销。

• 迅速释放。

保护组件
通过创建多个独立的堆栈,是数据隔离,且相互独立的操作。
更有效的内存管理

通过在堆栈中分配同样大小的对象,就可以更加有效地管理堆栈。就是把大小相同的对象放在一个堆栈中 进行分配。
进行本地访问

每当系统必须在R A M与系统的页文件之间进行R A M页面的交换时,系统的运行性能就会受到很大的影响。如果经常访问局限于一个小范围地址的内存,那么系统就不太可能需要在R A M与磁盘之间进行页面的交换。

所以,在设计应用程序的时候,如果有些数据将被同时访问,那么最好把它们分配在互相靠近的位置上。
减少线程同步的开销

正如下面就要介绍的那样,按照默认设置,堆栈是顺序运行的,这样,如果多个线程试图同时访问堆栈, 就不会使数据受到破坏。但是,堆栈函数必须执行额外的代码,以保证堆栈对线程的安全性。如果要进行大量的堆栈分配操作,那么执行这些额外的代码会增加很大 的负担,从而降低你的应用程序的运行性能。当你创建一个新堆栈时,可以告诉系统,只有一个线程将访问该堆栈,因此额外的代码将不执行。(就是用多个堆栈来 减少同步的性能消耗)
迅速释放堆栈

最后要说明的是,将专用堆栈用于某些数据结构后,就可以释放整个堆栈,而不必显式释放堆栈中的每个 内存块。例如,当Windows Explorer遍历硬盘驱动器的目录层次结构时,它必须在内存中建立一个树状结构。如果你告诉Windows Explorer刷新它的显示器,它只需要撤消包含这个树状结构的堆栈并且重新运行即可(当然,假定它将专用堆栈用于存放目录树信息)。对于许多应用程序 来说,这是非常方便的,并且它们也能更快地运行。

如何创建辅助堆栈

你可以在进程中创建辅助堆栈,方法是让线程调用H e a p C r e a t e函数:

HANDLE HeapCreate(
   DWORD fdwOptions,
   SIZE_T dwInitialSize,
   SIZE_T dwMaximumSize);









当试图从 堆栈分配一个内存块时, H e a p A l l o c函数(下面将要介绍)必须执行下列操作:

1) 遍历分配的和释放的内存块的链接表。

2) 寻找一个空闲内存块的地址。

3) 通过将空闲内存块标记为“已分配”分配新内存块。

4) 将新内存块添加给内存块链接表。

从堆栈中分配内存块

若要从堆栈中分配内存块,只需要调用H e a p A l l o c函数:

PVOID HeapAlloc(
   HANDLE hHeap,
   DWORD fdwFlags,
   SIZE_T dwBytes);









改变内存块的大小

常常需要改变内存块的大小。有些应用程序开始时分配的内存块比较大,然 后,当所有数据放入内存块后,再缩小内存块的大小。有些应用程序开始时分配的内存块比较小,后来需要将更多的数据拷贝到内存块中去时,再设法扩大它的大 小。如果要改变内存块的大小,可以调用H e a p R e A l l o c函数:

PVOID HeapReAlloc(
   HANDLE hHeap,
   DWORD fdwFlags,
   PVOID pvMem,
   SIZE_T dwBytes);









了解内存块的大小

当内存块分配后,可以调用H e a p S i z e函数来检索内存块的实际大小:

SIZE_T HeapSize(
   HANDLE hHeap,
   DWORD fdwFlags,
   LPCVOID pvMem);









释放内存块

当不再需要内存块时,可以调用H e a p F r e e函数将它释放:

BOOL HeapFree(
   HANDLE hHeap,
   DWORD fdwFlags,
   PVOID pvMem);









撤消堆栈

如果应用程序不再需要它创建的堆栈,可以通过调用H e a p D e s t r o y函数将它撤消:

BOOL HeapDestroy(HANDLE hHeap);









调用H e a p D e s t r o y函数可以释放堆栈中包含的所有内存块,也可以将堆栈占用的物理存储器和保留的地址空间区域重新返回给系统。如果该函数运行成功, H e a p D e s t r o y返回T R U E。如果在进程终止运行之前没有显式撤消堆栈,那么系统将为你将它撤消。但是,只有当进程终止运行时,堆栈才能被撤消。如果线程创建了一个堆栈,当线程终 止运行时,该堆栈将不会被撤消。

在进程完全终止运行之前,系统不允许进程的默认堆栈被撤消。如果将进程 的默认堆栈的句柄传递给H e a p D e s t r o y函数,系统将忽略对该函数的调用。

由于进程的地址空间中可以存在多个堆栈,因此可以使用G e t P r o c e s s H e a p s函数来获取现有堆栈的句柄:

DWORD GetProcessHeaps(
   DWORD dwNumHeaps,
   PHANDLE pHeaps);









若要调用G e t P r o c e s s H e a p s函数,必须首先分配一个H A N D L E数组,然后调用下面的函数:

HANDLE hHeaps[25];
DWORD dwHeaps = GetProcessHeaps(25, hHeaps);
if(dwHeaps > 5) 
{
   //More heaps are in this process than we expected.
} 
else
{
   //hHeaps[0] through hHeap[dwHeaps - 1]
   //identify the existing heaps.
}









注意,当该函数返回时,你的进程的默认堆栈的句柄也包含在堆栈句柄的数 组中。

H e a p Va l i d a t e函数用于验证堆栈的完整性:

BOOL HeapValidate(
   HANDLE hHeap,
   DWORD fdwFlags,
   LPCVOID pvMem);









调用该函数时,通常要传递一个堆栈句柄,一个值为0的标志(唯一的另一 个合法标志是H E A P _ N O _ S E R I A L I Z E),并且为p v M e m传递N U L L。然后,该函数将遍历堆栈中的内存块以确保所有内存块都完好无损。为了使该函数运行得更快,可以为参数p v M e m传递一个特定的内存块的地址。这样做可使该函数只检查单个内存块的有效性。

若要合并地址中的空闲内存块并收回不包含已经分配的地址内存块的存储器 页面,可以调用下面的函数:

UINT HeapCompact(
   HANDLE hHeap,
   DWORD fdwFlags);










通常情况下,可以为参数f d w F l a g s传递0,但是也可以传递H E A P _ N O _ S E R I A L I Z E。

下面两个函数H e a p L o c k和H e a p U n l o c k是结合在一起使用的:

<span

分享到:
评论

相关推荐

    内存堆栈分析工具MAT 64bit软件(Memory Analysis Tool)

    由于分析内存堆栈,基于Eclipse的插件开发的内存分析、内存泄漏分析工具,可以分析使用JConsole等工具dump出来的 .hrof内存dump文件,分析内存泄漏的内存信息,软件运维人员必备工具。

    内存、堆栈详解

    内存、堆栈详解内存、堆栈详解内存、堆栈详解内存、堆栈详解

    一个基于 C++的动态内存实时监测器设计与应用

    内存堆栈错误的目的,并以中国石化石油物探技术研究院自主研发的油气综合解释系统NEWS 子系统-叠前叠后联合解释模块主要流程为例,用该检测工具对其进行全面的测试与应用,实践表明,嵌入监测器的应用软件在开发过程...

    易语言申请进程堆栈内存

    易语言申请进程堆栈内存源码,申请进程堆栈内存,申请堆栈内存,取CPU型号_汇编版,释放堆栈内存,从堆栈分配内存_,释放堆栈内存_,取进程堆栈句柄_

    堆栈内存区别

    堆栈内存区别。

    堆栈与内存空间

    对堆栈和内存空间的详细描述,哪些是变量是在静态数据区分配的,动态分配是在堆上分配的

    Java堆栈内存分析笔记

    本人学习Java时苦找的内存分析我把它整理成WORD文档供大家学习Java堆栈内存分析笔记。

    STM32堆栈内存分析

    描述STM32堆栈是如何消耗,在内存中的位置如何,结合kile软件和启动文件分析。

    头歌实践教学平台 MIPS流水CPU设计---HUST

    本实验从 MIPS 单周期 CPU 开始逐步构建无冲突冒险的理想指令流水线,能处理分支相关的指令流水线,采用气泡处理数据相关的气泡式流水线...第9关:多级嵌套中断(EPC内存堆栈保存).txt (其余关卡还在持续更新当中……)

    关于堆栈、静态、动态内存的理解

    一个正常的程序在内存中通常分为程序段、数据端、堆栈三部分。程序段里放着程序的机器码、只读数据,这个段通常是只读,对它的写操作是非法的。数据段放的是程序中的静态数据。动态数据则通过堆栈来存放。 在内存中...

    TCPIP 通信协议堆栈报告内存已用完

    TCPIP 通信协议堆栈报告内存已用完,具体处理步骤,简单易学。

    CDMA软件介绍 程序内存和堆栈

    简单介绍CDMA终端开发过程中的程序内存和堆栈的问题

    易语言源码易语言申请进程堆栈内存源码.rar

    易语言源码易语言申请进程堆栈内存源码.rar 易语言源码易语言申请进程堆栈内存源码.rar 易语言源码易语言申请进程堆栈内存源码.rar 易语言源码易语言申请进程堆栈内存源码.rar 易语言源码易语言申请进程堆栈内存...

    头歌实践教学平台 MIPS CPU设计(HUST)

    本实训项目将帮助学生掌握 CPU 控制器设计的基本原理,能利用硬布线控制器的设计原理在 Logisim 平台中设计实现支持五条指令的 MIPS 单周期 CPU,该处理器能...第8关:单周期CPU多级中断机制设计---内存堆栈(构建中)

    Delphi枚举内存堆.rar

    Delphi枚举指定进程的内存堆,也就是枚举指定程序的内存,枚举出内存堆栈ID、内存基地址、占用内存大小以及标志等,程序还需改进,有些内存堆栈是枚举不到的。

    操作系统面试题目.pdf

    1、什么是进程(Process)和线程(Thread)?有何区别? 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活 动,... 内存堆栈,最适合用来管理大量的小对象。 Windows操纵内存可以分两个层面:物理内存和

    操作系统面试题目.doc

    1、什么是进程(Process)和线程(Thread)?有何区别? 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动...内存堆栈,最适合用来管理大量的小对象。 Windows操纵内存可以分两个层面:物理内存和虚拟内

    MIPS CPU设计(HUST).zip

    全部关卡,复制txt,满分过,方便快捷

    C语言程序设计课程中的计算思维探析_汪红兵.pdf

    法操作支持下顺序自动地执行以及函数之间的调用在内存堆栈区支持下自动地进行跳转。最 后,针对计算思维的抽象和自动化特征,给出了 C 语言程序设计课程在教学内容、教学方式 和考核内容上的一些建议和措施。

    易语言申请进程堆栈内存源码

    易语言申请进程堆栈内存源码。@资源源码站。

Global site tag (gtag.js) - Google Analytics