zoukankan      html  css  js  c++  java
  • 进程的默认堆与自建堆

    最近去了一次面试,面试官问道这个进程的自建堆和默认堆的相关问题,我当时感觉答的并不是很好,这时候我决定好好整理一下相关知识跟大家分享。

    进程默认堆:
    Windows许多重要的函数都用Unicode字符和Unicode字符串来执行它们所有的操作。如果我们调用的是一个函数的ANSI版本,那么该函数的ANSI版本必须把ANSI字符串转换为Unicode字符串,然后再调用同一个函数的Unicode版本。为了转换字符串,ANSI版本的函数需要分配一块内存来保存Unicode版本的字符串,这块内存就是从进程的默认堆中分配的。默认堆大小一般为1M,可以在编译器设置/HEAP。
    进程自建堆:
    为什么要创建额外的堆:
    1.对组件进行有效的保护
    2.更有效的内存管理
    3.使内存访问局部化
    4.避免线程的同步开销
    5.快速释放

    1.对组件进行保护
    举个栗子:有一个链表和一个二叉树都需要保存在同一个堆中,这会使两种结构混合,假如链表中的某个节点出错覆盖他下边的某块内存,就可能把二叉树结构破坏,这会导致定位出错很难,于是把两种结构放到两个堆中,这种可能性就会小很多。
    2.更有效的内存管理:
    每个堆保证相同的结构会使内存分配更为合理。再举上一个栗子,链表每个节点大小为24字节,二叉树每个节点32字节,现在链表释放了2个节点,这时有了48字节的空间,但是很有可能这两块内存不连续。而没法给二叉树分配一个节点的空间。如此操作,会使堆内内存碎片化。
    3.使内存访问局部化
    我们知道系统在访问内存的时候会产生页交换,当系统把一个内存页换入到磁盘中,再从磁盘中换出一个内存页时,这种消耗是十分巨大的。于是,把相同的节点放在一个内存堆中就显得尤为重要了。继续举栗子,当我们一个堆中只保存链表节点,或者只保存二叉树节点,这个时候内存很有可能分配到邻近一块儿内存中,这时候我们遍历节点就不需要再进行页交换了。但是两个结构混用的话,很有可能看似相邻的两个节点其实在两个页交换文件中,如果运气差,有可能进行一次遍历,系统需要多次进行页交换,大大降低了效率。
    4.避免线程同步的开销
    在默认情况下,系统中线程对堆的访问是依次进行的,如果你自己创建了堆,系统将不会用额外代码来保证线程的安全性,就会在一定程度上减小系统的消耗,不过这时候对堆的内存操作将有我们自己进行,系统将不再管理。
    5.快速释放
    如果我们创建一个堆来存放数据,我们在销毁数据的时候可以仅仅将整个堆的内存释放,而不必一个个节点去释放,大大加快了释放内存的效率。

    如何创建额外的堆
    我们可以调用HeapCreate函数来创建额外的堆。函数原型如下:
    HANDLE
    WINAPI
    HeapCreate(
        _In_ DWORD flOptions,         //表示对堆的操作应该如何进行
        _In_ SIZE_T dwInitialSize,    //表示一开始系统调拨给堆的字节数,如果需要系统会将这个值向上取整到CPU页面的整数倍
        _In_ SIZE_T dwMaximumSize     //向上取整最大字节数
        );
    


  • 相关阅读:
    idea删除module
    使用腾讯云mysql的一下小坑
    docker 从 tomcat 容器连接到 mysql 容器
    数据结构开发(16):选择排序和插入排序
    数据结构开发(15):递归的思想与应用
    数据结构开发(14):KMP 子串查找算法
    数据结构开发(13):字符串类的创建
    数据结构开发(11):双向循环链表的实现
    数据结构开发(10):Linux内核链表
    数据结构开发(9):循环链表与双向链表
  • 原文地址:https://www.cnblogs.com/Toring/p/6628266.html
Copyright © 2011-2022 走看看