堆栈详解

一 首先介绍下堆和堆栈(堆栈)的是什么,区别是什么?

注意,其实堆栈本身就是栈(stack)。通俗易懂说,堆栈==栈, 堆==堆(heap)

1.堆:什么是堆?又该怎么理解呢?

答:1,堆(heap)是一种数据结构,堆控制一段自己的存储空间,叫做堆空间。

       2,堆是在程序运行时申请的动态内存,而不是在程序编译时,申请某个大小的内存空间。

       3,堆是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程。

2. 栈(堆栈):什么是堆栈?又该怎么理解呢?

       1,栈(stack)又名堆栈是操作系统在建立某个进程时或者线程,为这个线程建立的存储区域,在编译的时候可以指定需要的栈的大小

       2,栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。

       2,栈好比一个桶,放进去的先拿出来,它下面本来有的东西要等它出来之后才能出来(先进后出)。

二 栈(堆栈)的操作原理

1.栈的简介  :栈是一个在计算机科学中经常使用的抽象数据类型。栈中的物体具有一个特性: 最后一个放入堆栈中的物体总是被最先拿出来, 这个特性通常称为后进先出队列。 堆栈中定义了一些操作。 两个最重要的是PUSH和POP。 PUSH操作在堆栈的顶部加入一个元素。POP操作相反, 在堆栈顶部移去一个元素, 并将堆栈的大小减一。给个简图理解下

先进后出队列堆栈好比这个容器放入时是先放入1其次2然后3,当要取出时,只能先取出3其次2然后1.

2.栈的操作原理

         栈在程序运行中的作用非常重要,它保存了一个函数调用所需要维护的信息,称为现场保护,当函数调用结束后需要返回主函数,这时候就需要现场信息,要保护的现场信息包括(如图)ebp :是栈低指针,esp是栈顶指针,

         1. 函数的返回地址,参数

         2. 临时变量

        3. 上下文:寄存器

 

    

3.举例说明堆操作

1 当主函数里执行调运函数时先将把参数按照从右至左的顺序压栈,比如changenumber(num1,num2);

    先将num2入栈再将num1入栈,此顺序十分重要,以后我会举例说明其重要性。

2 将主函数当前指令的下一条指令入栈,即为保存被调函数执行结束后要执行的下一条指令。

3开始执行被调函数,先保存旧地址old ebp,和寄存器里的重要数据。局部变量:将

num1,num2的值复制一份保存在被调函数里的空间,其空间顺序为num1,num2其次看图

所以这里主函数的num1值对应着被调函数的num1的值,主函数num2对应着被调函数的num2值。具体例子我会在发表一篇博客

当被调函数执行结束后,把old ebp读回寄存器,然后从return address开始执行,原来的ebp成为新的esp。

那么,函数的返回值是如何传递的呢?

       答案:通过eax寄存器。函数将返回值存储在eax中,然后调用方读取eax。但是,eax本身只有4个字节,大于4个字节的返回值,则是通过eax存储了一个指针,而实际内容在栈上的其他地方。初学具体我也不是很清楚,望见谅

三 堆的操作原理

1 堆简介用于动态分配内存,c语言中使用malloc/free进行申请和释放。申请空间这种事一般都是有操作系统来做,但是在编程是我们需要经常申请空间,就需要经常调用系统代码。在用户状态与内核态之间切换,也就是频繁的调用中断处理程序,导致性能较差,但事实上不是这样的,比如在写c语言代码时,都是通过调运运行库封装好的库函数,而库函数里提前申请好一段适当大的内存,给编程用,当我们需要申请空间时,对于小空间直接向库函数里取相应大小的空间即可,这样就提高了性能。.

2.操作原理(简述):

堆是一块巨大的内存空间,程序员通过申请得到了该空间的使用权。一般操作给的是一块连续的存储空间,而在操作系统哪里,它只记录它分配空间的初始地址和大小,当free时将初始地址归入操作系统的空闲空间。比如以下操作。  

int main() { 
    char *p = (char*)malloc(100); 
    free (p)
}

上面的程序用malloc申请了1000个字节的空间后,程序可以自由地使用这100个字节,直到程序用free函数释放它。

四.堆,栈,空间在哪里使用(以C 和 Java为例)

    1.堆使用:c语言:malloc ,calloc 操作(目前只知道这两个)

      Java:堆空间由Java运行时用于为Objects和JRE类分配内存。每当我们创建(new)任何对象时,它总是在堆空间中创建。垃圾收集在堆内存上运行,以释放没有任何引用的对象使用的内存。在堆空间中创建的任何对象都具有全局访问权限,可以从应用程序的任何位置引用.

    2 栈使用:c语言:局部变量,存放函数的参数名,如int a;

     Java : 栈内存用于执行线程。栈内存包含生命周期短的方法特定值及以及对从该方法引用的堆中其他对象的引用。用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

五 堆、栈区别总结:

1.堆和栈空间分配

 ①栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

 ②堆(操作系统): 一般由程序员分配释放比如(malloc), 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

2.堆和栈缓存方式

①栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。

②堆则是存放在二级缓存中,生命周期由虚拟机(比如JVM)的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。

3.堆栈数据结构区别

①堆(数据结构):堆可以被看成是一棵树,如:堆排序。

②栈(数据结构):一种先进后出的数据结构。

  • 40
    点赞
  • 239
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
在Java中,我们可以通过创建自定义异常来提供更详细的错误信息。自定义异常类继承自Java提供的Exception或其子类,对于需要打印非堆栈信息的自定义异常,我们可以通过重写Exception类的toString()方法来实现。 在自定义异常类中,我们可以添加额外的成员变量来保存非堆栈信息,例如错误代码、错误描述等。然后,在toString()方法中,可以通过格式化字符串的方式将这些信息打印出来。 以下是一个示例的自定义异常类: ```java public class MyException extends Exception { private int errorCode; private String errorMessage; public MyException(int errorCode, String errorMessage) { this.errorCode = errorCode; this.errorMessage = errorMessage; } @Override public String toString() { return "错误代码:" + errorCode + "\n错误描述:" + errorMessage; } } ``` 在使用该自定义异常类的时候,我们可以通过创建异常对象,并将非堆栈信息传递给构造方法来初始化异常对象。当异常被抛出并捕获时,可以通过调用异常对象的toString()方法来获取非堆栈信息并打印出来。 以下是一个使用自定义异常类的示例: ```java public class Main { public static void main(String[] args) { try { throw new MyException(1001, "自定义异常测试"); } catch (MyException e) { System.out.println(e.toString()); } } } ``` 运行上述代码,将输出自定义异常的非堆栈信息: ``` 错误代码:1001 错误描述:自定义异常测试 ``` 通过重写Exception类的toString()方法,我们可以自定义异常的非堆栈信息的格式和内容,从而提供更详细的错误信息供调试和日志记录使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值