java递归栈溢出问题排查_内存碎片


● 请说一说你理解的stack overflow,并举个简单例子导致栈溢出

参考回答:

栈溢出概念:

栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致栈中与其相邻的变量的值被改变。

栈溢出的原因:

1. 局部数组过大。当函数内部的数组过大时,有可能导致堆栈溢出。局部变量是存储在栈中的,因此这个很好理解。解决这类问题的办法有两个,一是增大栈空间,二是改用动态分配,使用堆(heap)而不是栈(stack)。

2. 递归调用层次太多。递归函数在运行时会执行压栈操作,当压栈次数太多时,也会导致堆栈溢出。

3. 指针或数组越界。这种情况最常见,例如进行字符串拷贝,或处理用户输入等等。

栈溢出例子:

#include #include int main(int argc, char* argv[]) {char buf[256];strcpy(buf,argv[1]);printf("Input:%s",buf);return 0;}

上述代码中的strcpy(buf,argv[1]);这一行发生了缓冲区溢出错误,因为源缓冲区内容是用户输入的。


● 请你回答一下栈和堆的区别,以及为什么栈要快

参考回答:

堆和栈的区别:

堆是由低地址向高地址扩展;栈是由高地址向低地址扩展

堆中的内存需要手动申请和手动释放;栈中内存是由OS自动申请和自动释放,存放着参数、局部变量等内存

堆中频繁调用malloc和free,会产生内存碎片,降低程序效率;而栈由于其先进后出的特性,不会产生内存碎片

堆的分配效率较低,而栈的分配效率较高

栈的效率高的原因:

栈是操作系统提供的数据结构,计算机底层对栈提供了一系列支持:分配专门的寄存器存储栈的地址,压栈和入栈有专门的指令执行;而堆是由C/C++函数库提供的,机制复杂,需要一些列分配内存、合并内存和释放内存的算法,因此效率较低。


● 手写代码:两个栈实现一个队列

参考回答:

class Solution{public:void push(int node) {stack1.push(node);}int pop() {if(stack2.size()!=0){int tmp = stack2.top();stack2.pop();return tmp;}else{while(stack1.size()!=0){int tmp = stack1.top();stack1.pop();stack2.push(tmp);}return pop();}}  private:stack stack1;stack stack2; };

● 请你来说一下堆和栈的区别

参考回答:

1)申请方式:

栈由系统自动分配和管理,堆由程序员手动分配和管理。

2)效率:

栈由系统分配,速度快,不会有内存碎片。

堆由程序员分配,速度较慢,可能由于操作不当产生内存碎片。

3)扩展方向

栈从高地址向低地址进行扩展,堆由低地址向高地址进行扩展。

4)程序局部变量是使用的栈空间,new/malloc动态申请的内存是堆空间,函数调用时会进行形参和返回值的压栈出栈,也是用的栈空间。


● 请你说一说小根堆特点

参考回答:

堆是一棵完全二叉树(如果一共有h层,那么1~h-1层均满,在h层可能会连续缺失若干个右叶子)。

1)小根堆

若根节点存在左子女则根节点的值小于左子女的值;若根节点存在右子女则根节点的值小于右子女的值。

2)大根堆

若根节点存在左子女则根节点的值大于左子女的值;若根节点存在右子女则根节点的值大于右子女的值。