• 前端中堆和栈的概念


    !!!内容整理自各大博客+理解!!!

    内存中堆和栈概念

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

    • 堆:队列优先,先进先出;动态分配的空间 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表。

    堆与栈区别

    堆与栈实际上是操作系统对进程占用的内存空间的两种管理方式,主要有如下几种区别: (1)管理方式不同。栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏

    (2)空间大小不同。每个进程拥有的栈的大小要远远小于堆的大小。理论上,程序员可申请的堆大小为虚拟内存的大小,进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB;

    (3)生长方向不同。堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。

    (4)分配方式不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由操作系统进行释放,无需我们手工实现。

    (5)分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。

    (6)存放内容不同。栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等。当主函数调用另外一个函数的时候,要对当前函数执行断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,即扩展指针寄存器的内容(EIP),然后是当前栈帧的底部地址,即扩展基址指针寄存器内容(EBP),再然后是被调函数的实参等,一般情况下是按照从右向左的顺序入栈,之后是被调函数的局部变量,注意静态变量是存放在数据段或者BSS段,是不入栈的。出栈的顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来填充的。

    从以上可以看到,堆和栈相比,由于大量malloc()/free()或new/delete的使用,容易造成大量的内存碎片,并且可能引发用户态和核心态的切换,效率较低。栈相比于堆,在程序中应用较为广泛,最常见的是函数的调用过程由栈来实现,函数返回地址、EBP、实参和局部变量都采用栈的方式存放。虽然栈有众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,主要还是用堆。

    无论是堆还是栈,在内存使用时都要防止非法越界,越界导致的非法内存访问可能会摧毁程序的堆、栈数据,轻则导致程序运行处于不确定状态,获取不到预期结果,重则导致程序异常崩溃,这些都是我们编程时与内存打交道时应该注意的问题。

    数据结构中的堆和栈

    这里不做讨论,其他资料已经写的很明白了

    与前端相关的内容

    JavaScript的数据类型有两大类

    基本类型

    包含null、undefined、Number、String、Boolean,ES6还多了一种Symbol

    基本数据类型可以直接访问,他们是按照值进行分配的,存放在栈(stack)内存中的简单数据段,数据大小确定,内存空间大小可以分配。

    引用型

    即Object ,是存放在堆(heap)内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置。

    概念闲扯

    讲到了堆栈内存那么自然就会牵扯到了闭包、浅拷贝、深拷贝然后就会扯到call、bind、apply

    先来扯一下浅拷贝和深拷贝

    首先!!!!记得只有引用类型才有浅拷贝深拷贝这么 一说,基本数据类型雨女无瓜

    最常用的深拷贝:序列法和反序列法

    // 序列化反序列化法
    function deepClone(obj) {
       return JSON.parse(JSON.stringify(obj))
    }

    在我的面试笔记里,还有更详细的方法,转载自一个博客大佬,真可谓把深拷贝浅拷贝完全剖析

    以下为该大佬地址

    https://www.jianshu.com/p/b08bc61714c7

    再来扯一下闭包

    闭包我个人的理解就是他是一个函数,可以访问别人作用域内变量的函数

    闭包需要理解以下案例

    var name = "The Window";
    var object = {
      name: "My Object",
      getNameFunc: function() {
        return function() {
          return this.name;
        };
      }
    };
    alert(object.getNameFunc()()); //The Window
    ​
    var name = "The Window";
    var object = {
      name: "My Object",
      getNameFunc: function() {
        var that = this;
        return function() {
          return that.name;
        };
      }
    };
    alert(object.getNameFunc()()); //My Object
    ​
    function fun(n, o) {
      console.log(o);
      return {
        fun: function(m) {
          return fun(m, n);
        }
      };
    }
    var a = fun(0);
    a.fun(1);
    a.fun(2);
    a.fun(3); //undefined,?,?,?
    var b = fun(0)
      .fun(1)
      .fun(2)
      .fun(3); //undefined,?,?,?
    var c = fun(0).fun(1);
    c.fun(2);
    c.fun(3); //undefined,?,?,?
    ​
    

      

    call bind apply 引用大佬文章,每次忘记都看一遍!舒服

    JS基础-面试官想知道你有多理解call,apply,bind?[不看后悔系列]

    https://juejin.im/post/5d469e0851882544b85c32ef

  • 相关阅读:
    (Java) LeetCode 44. Wildcard Matching —— 通配符匹配
    (Java) LeetCode 30. Substring with Concatenation of All Words —— 与所有单词相关联的字串
    (Java) LeetCode 515. Find Largest Value in Each Tree Row —— 在每个树行中找最大值
    (Java) LeetCode 433. Minimum Genetic Mutation —— 最小基因变化
    (Java) LeetCode 413. Arithmetic Slices —— 等差数列划分
    (Java) LeetCode 289. Game of Life —— 生命游戏
    (Java) LeetCode 337. House Robber III —— 打家劫舍 III
    (Java) LeetCode 213. House Robber II —— 打家劫舍 II
    (Java) LeetCode 198. House Robber —— 打家劫舍
    (Java) LeetCode 152. Maximum Product Subarray —— 乘积最大子序列
  • 原文地址:https://www.cnblogs.com/liuarui/p/11321441.html
Copyright © 2020-2023  润新知