Logo
【基础】堆和栈
所属分类:技术分享
阅读量:76
评论数量:0
发布时间:2025-02-05 16:58

内存中堆和栈对比

管理方式

  • 堆堆需要程序员手动进行分配和管理。
  • 栈是由系统自动分配和管理的

内存大小

  • 栈的大小是固定的,由操作系统指定
  • 堆空间通常由系统分配初始大小,程序员可以自由地调整大小。

存储方式

  • 栈 基本数据类型 对象的引用
  • 堆heap 存储动态分配的对象和复杂数据结构类型比如对象 数组 函数 image.png

堆和栈的优化

内存管理的优化

  • 内存池 在程序开始时一次性地申请大块内存,然后将这块内存划分成若干个小块使用。这样做可以减少频繁申请和释放内存的开销。
  • 对齐 对齐是指将变量和数据结构在内存中的地址按照规定的字节边界对齐。如果按照规定的字节边界对齐,会使访问内存时的开销变得更小。
  • 缓存 由于缓存中读取和写入内存的速度快,因此可以将经常访问的数据放到缓存中。这样可以减少从内存中读取数据的次数,从而优化程序性能。
  • 内存映射文件 内存映射文件是指将一个文件映射到进程的虚拟内存地址空间中,这样就可以像使用普通内存一样读取和写入文件。这样可以显著地加快文件的读写速度。
  • 虚拟内存 虚拟内存是一种将物理内存和硬盘上的空间组合起来使用的技术。通过虚拟内存,程序可以访问比物理内存更大的内存空间。
  • 智能指针 智能指针是一种可以自动管理内存生命周期的指针。使用智能指针可以避免内存泄漏和野指针等问题。
  • 垃圾回收(GC) 垃圾回收是一种自动内存管理机制,通过定期扫描堆中的对象,找出不再使用的对象并释放其占用的内存。这样可以避免内存泄漏和野指针等问题。
  • NUMA架构 NUMA是一种计算机系统的架构,通过将物理内存划分成若干个节点,来减少处理器和内存之间的访问延迟。采用NUMA架构可以提高系统的性能。

栈空间的优化

  • 减少局部变量的使用
  • 减少递归深度 递归是一种函数调用自身的机制,如果递归深度过大,就会消耗大量的栈空间。因此,采用非递归的方式来实现递归函数,或者通过优化递归算法来减少递归深度,都可以减小栈的空间消耗。
  • 减少参数的数量 函数的参数和局部变量都会占用栈空间。因此,减少参数的数量可以减小栈的空间消耗。如果有多个参数需要传递,可以考虑将它们打包成一个结构体或对象,从而减少参数的数量。
  • 使用堆空间 在某些情况下,如果栈空间不够用,可以考虑使用堆空间来分配内存。需要注意的是,使用堆空间会带来动态内存分配和释放的开销,因此需要谨慎使用。

堆空间的优化

  • 内存池 内存池是一种预先分配大块的内存,然后将这些内存分配给需要使用的对象。这样可以减少频繁地申请和释放内存带来的开销,提高程序的性能。

  • 缓存 由于动态内存分配和销毁的开销较大,执行频繁可能导致程序性能下降。为此,可以在程序运行过程中维护一定量的空闲内存,如果需要分配内存时可以先在空闲内存分配。

  • 立即释放内存 内存泄漏是指程序在使用完一块内存后没有及时释放,最终导致程序占用过多内存。因此,在使用完内存后,必须将其及时释放。

  • 对象池 对象池是一种将多个相同类型的对象存储在一起的数据结构,这样多个对象可以共享同一块连续的内存。对象池一般配合内存池来使用,能够更好地管理内存。

  • 减少内存碎片 内存碎片是指连续的内存块中有一些 unused 空间不足以满足新的内存分配请求。减少内存碎片可以通过内存池来达成。

  • 聚合对象 聚合对象是指将多个对象聚合到一起,避免分散的内存分配。聚合对象的方式可以包括数组、结构体等。

堆和栈的安全问题

栈溢出的原因

  • 栈溢出的原因可以包括:
  • 函数嵌套调用过多:当函数嵌套调用过深或递归调用没有结束,而函数的上下文信息已经超过栈容量时,便会产生栈溢出。
  • 局部变量存储空间过大
  • 缓冲区溢出 当向栈缓冲区内写入的数据超过缓冲区的大小时,也会导致栈溢出

堆溢出的原因

  • 内存泄漏:如果没有及时释放已经分配的内存,会导致内存占用越来越多,最终导致堆溢出。
  • 缓冲区溢出:当向堆缓冲区内写入的数据超过缓冲区的大小时,也会导致堆溢出。
  • 不正确的内存处理:在程序中错误使用指针或动态内存分配函数,例如使用已经被释放的指针或尝试释放非动态内存等,也会导致堆溢出。

栈溢出的危害

  • 程序崩溃:当程序发生栈溢出时,会导致程序崩溃,从而影响系统的稳定性和可靠性。
  • 数据损坏:栈溢出会导致内存中的数据被破坏,从而导致数据错误或损坏,影响程序的正确运行。
  • 安全漏洞:当栈溢出时,攻击者可以改变函数返回地址,从而将程序控制权转移到恶意代码上,导致系统安全漏洞。

堆溢出的危害

  • 程序崩溃:当程序发生堆溢出时,会导致程序崩溃,从而影响系统的稳定性和可靠性。
  • 数据损坏:堆溢出会导致内存中的数据被破坏,从而导致数据错误或损坏,影响程序的正确运行。
  • 安全漏洞:当堆溢出时,攻击者可以改变程序的控制流,将程序控制权转移到恶意代码上,导致系统安全漏洞,例如缓冲区溢出漏洞和堆溢出漏洞。跨站脚本攻击(XSS)就是一种堆溢出漏洞造成的安全漏洞类型。

如何防止栈和堆溢出

  • 减少嵌套调用深度:尽量减少函数的嵌套调用深度,避免无限递归和函数调用过程中占用过多的栈空间。
  • 减少局部变量的使用:可以尝试使用静态变量或全局变量来避免函数调用过深,减少局部变量的使用可以减小栈空间的消耗。
  • 缓冲区检查:使用具有缓冲区检查功能的编程语言,例如 Java 或 C#,可以在编译过程中检查缓冲区溢出问题。
  • 使用内存池:使用内存池可以减少动态内存分配和销毁的开销,提高程序效率。
  • 立即释放内存:尽可能的及时释放已经分配的内存,避免内存泄漏,特别是在程序用完一个指针后,要立即释放它所指向的内存空间。
  • 限制缓存区大小:在分配缓存区时,应该限制缓存区大小,避免产生缓冲区溢出。
  • 安全编程实践:程序员应该注意编写安全的程序,避免调用不安全的函数或不安全的指针操作,应该注意编写完整、健壮、可靠的代码。
标签

作者:suckson

版权:此文章版权归 suckson 所有,如有转载,请注明出处!

空状态
评论列表为空~
目录
豫ICP备18022290号
月亮搜索返回顶部