太原市建设局网站,桂林哪里可以做网站,营销型网站建设选择题,怎样在阿里云做网站首先提出一道经典的面试题来引出今天的主角#xff1a; 进程的虚拟空间分布是什么样的#xff0c;全局变量放在哪里#xff1f; 在数据初始化之后#xff0c;全局变量放在.data段 在数据未初始化时#xff0c;全局变量放在.bss段
内存五区
进程虚拟内存主要分为五个部分…首先提出一道经典的面试题来引出今天的主角 进程的虚拟空间分布是什么样的全局变量放在哪里 在数据初始化之后全局变量放在.data段 在数据未初始化时全局变量放在.bss段
内存五区
进程虚拟内存主要分为五个部分
栈区自上而下堆区自下而上全局区也叫做静态区也就是用户栈常量区程序代码区 在内核虚拟内存中物理内存、内核代码和数据对于每一个进程都是一样的。 唯一不同的是进程相关的数据结构。 栈区
栈区是自上而下的扩展的是一块连续的内存空间。栈和堆总共的空间大小在一开始就被规定好了。他们都会随着程序的进行而发生变化。
栈是由系统自动分配的速度很快并且释放的也很快程序员无法主动去控制栈的释放。如果在栈申请时没有剩余的空间就会出现OOM的情况。
栈主要用来存放局部变量和函数参数。比如你的递归函数函数内部声明的变量等。
堆区
堆区是自下而上的扩展的是一块不连续的内存空间。这一点和栈完全相反。
堆在程序启动初期会根据程序分配内存空间并且在程序运行期间仍会继续分配。程序员是可以主动去申请堆内存的分配方式类似于链表申请的时候会以遍历的方式在堆中找到一块合适的内存块。然后将该内存块从空闲结点中删除掉。
存储在堆中的内存是需要程序员去手动释放掉的。如果不释放这些资源就会导致内存一直被占用最终变得越来越多。因此许多语言在继C/C之后采用了垃圾回收机制。垃圾回收机制可以帮助程序员主动的释放掉不会再次使用的申请在堆内存上的变量它可以让程序员更好的关注于业务而不是释放资源。 注意频繁的释放堆内存也会造成碎片化的问题因此尽量不要频繁的创建和释放堆资源。 全局静态区
全局区主要用来存放全局变量和在编译器就能够确定的static值。因此这一块在程序编译时就已经被分配好内存空间了。
全局变量和静态变量是放在一块的。初始化的全局变量和静态变量在同一个区域内未初始化的全局变量和静态变量在相邻的另一个区域内。
优点在于不用主动去分配由操作系统自动分配速度快因为编译期就能被确定并且不容易出错。
文字常量区
常量在统一运行被创建常量区的内存是只读的程序结束后由系统释放。
程序代码区
存放二进制代码的地方。
总结
进程的虚拟空间可以分为五大部分栈、堆、全局区、常量区、程序代码区。
其中栈和堆的比较重要他们的主要区别有
栈的地址是自上而下递减的堆的地址是自下而上递增的。注意虚拟空间的地址是从下到上依次递增的栈只能由系统控制分配和释放。而堆可以由程序员调用malloc/newAPI函数分配并且由程序员主动的去释放资源。栈是机器系统提供的数据结构计算机会在底层对栈提供支持分配专门的寄存器存放栈的地址压栈出栈都有专门的指令执行这就决定了栈的效率比较高。而堆是由语言进行实现的一个内存区。由语言中的函数进行调用和释放。堆中的内存经常需要进行整理才能获得更大的内存空间。频繁的创建和删除堆资源会产生碎片化问题因为堆的申请方式跟栈不一样堆是在内存空间中挑的一块合适的地方。而栈是一段连续的内存。并且栈释放的时候也是挨着释放的因为出栈的肯定是要从栈顶出。
那么我们上述说了频繁的释放堆资源会造成碎片化的问题而项目中又经常会用到堆资源那有没有好的解决办法呢
答案就是内存池技术
什么是内存池
**内存池(Memory Pool)**是一种内存分配方式。通常我们习惯直接使用new、malloc等API申请分配内存。这样做的缺点在于所申请内存块的大小不定当频繁使用时会造成大量的内存碎片并进而降低性能。
内存池诞生原因 默认内存管理函数的不足 利用默认的内存管理函数new/delete或malloc/free在堆上分配和释放内存会有一些额外的开销。
系统在接收到分配一定大小内存的请求时首先查找内部维护的内存空闲块表并且需要根据一定的算法例如分配最先找到的不小于申请大小的内存块给请求者或者分配最适于申请大小的内存块或者分配最大空闲的内存块等找到合适大小的空闲内存块。
如果该空闲内存块过大还需要切割成已分配的部分和较小的空闲块。然后系统更新内存空闲块表完成一次内存分配。类似地在释放内存时系统把释放的内存块重新加入到空闲内存块表中。如果有可能的话可以把相邻的空闲块合并成较大的空闲块。
默认的内存管理函数还考虑到多线程的应用需要在每次分配和释放内存时加锁同样增加了开销。可见如果应用程序频繁地在堆上分配和释放内存则会导致性能的损失。并且会使系统中出现大量的内存碎片降低内存的利用率。
默认的分配和释放内存算法自然也考虑了性能然而这些内存管理算法的通用版本为了应付更复杂、更广泛的情况需要做更多的额外工作。而对于某一个具体的应用程序来说适合自身特定的内存分配释放模式的自定义内存池则可以获得更好的性能。
内存池的分类
应用程序自定义的内存池根据不同的适用场景又分为不同的类型。
从线程安全的角度上来看内存池可以分为单线程内存池和多线程内存池。 单线程内存池整个生命周期只被一个线程使用无需考虑互斥访问的情况。 多线程内存池需要被多个线程共享因此在每次分配和释放内存时都需要加锁。
相对而言单线程内存池性能更好多线程内存池适用范围更广。
内存池有什么优点
内存池会在你实例化对象分配内存的时候预先给你分配一定数量、大小相等的内存块。当这些内存不够使用的时候会从内存池中分出一部分新的内存块来使用。如果内存块也不够的话会再申请新的内存。 这样做的显著优点就是提高了内存分配效率。 经典内存池技术
**内存池Memory Pool**技术因为其对内存管理有着显著的优点在各大项目中应用广泛备受推崇。但是通用的内存管理机制要考虑很多复杂的具体情况如多线程安全等难以对算法做有效的优化所以在一些特殊场合实现特定应用环境的内存池在一定程度上能够提高内存管理的效率。
经典的内存池Memory Pool技术是一种用于分配大量大小相同的小对象的技术。通过该技术可以极大加快内存分配/释放过程。既然针对是特定对象的内存池所以内存池一般设置为类模板根据不同的对象来进行实例化。
经典内存池如何实现
先申请一块连续的内存空间该段内存空间能够容纳一定数量的对象。每个对象连同一个指向下一个对象的指针一起构成一个内存节点Memory Node。各个空闲的内存节点通过指针来形成一个链表链表的每一个内存节点都是一块可供分配的内存空间。某个内存节点一旦分配出去就将从链表中去除。一旦释放了某个内存节点的空间又将该节点重新加入自由内存节点链表。如果一个内存块的所有内存节点分配完毕若程序继续申请新的对象空间则会再次申请一个内存块来容纳新的对象。新申请的内存块会加入内存块链表中。
参考资料
进程虚拟空间分布 - Jeff的技术栈 - 博客园 (cnblogs.com)
内存池介绍与经典内存池的实现 - 腾讯云开发者社区-腾讯云 (tencent.com)