JavaScirpt中的内存分配

内存的分类

内存主要分为两种:栈内存和堆内存

栈内存

栈内存用来控制程序的执行流程
就Java来说 程序的入口是main方法 首先将main压入栈内 执行到下一个方法foo时 将foo压入栈中 foo方法调用bar方法时 将bar压入栈中 然后按bar -> foo -> main 的顺序依次把它们弹出 整个程序执行完毕

JavaScript也是这样子的 只不过有一点区别 就是JavaScript不需要显示的指定main方法 所有的JavaScript代码默认都是在隐式的main方法里 这可能会让大家不习惯 这种从上到下像面条一样的代码

语言本身给我们带来的特性是没有好坏的 特性本身是用来解决问题的 如何去使用这些特性就要靠我们自己去选择了
我在写JavaScript会创建一个main 方法来作为我的主函数 整个在代码的流程都在这里执行 这样整个逻辑就非常清晰了

栈内存还可以存基本的数据类型和引用类型的地址 当程序需要操作基本类型的时候就直接把栈中的东西拿出来就可以了 操作引用类型时先把地址拿回来 然后根据这个地址去堆内存中找到对应的对象

这些变量是存在作用域的 它们随着函数push stack 被创建 并且在 pop stack的时候被销毁

堆内存

堆内存用来存引用类型 不像栈内存 堆内存就像一个院子 没有顺序

栈内存是静态的 而堆内存是动态的

内存的生命周期

  1. 分配
  2. 使用
  3. 释放

在c语言中提供了对内存进行管理的接口
而在JavaScript中不需要程序员直接操作内存 因为JavaScript提供了内置的垃圾回收机制 当内存不需要的时候就会自动的回收

如何判断那些内存可以被回收

  1. 引用计数
    这是最简单的垃圾收集算法。对象如果没有其他对象引用到它。对象将被垃圾回收机制回收。
    该算法有个限制:无法处理循环引用
    1
    2
    3
    4
    5
    6
    var div;
    window.onload = function(){
    div = document.getElementById("myDivElement");
    div.circularReference = div;
    div.lotsOfData = new Array(10000).join("*");
    };

myDivElement 一直存在一个自身的引用 即使他在DOM树中移除了 该内存也不会被释放

  1. 标记清除

假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象)。定期的,垃圾回收器将从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和所有不能获得的对象 这个算法解决了循环引用的问题。

具体的触发垃圾回收的情况又很复杂这里就不再继续研究了。
以上就是我对内存的理解。

参考
MDN 内存管理