读《代码的未来》

远子 â€¢  2020å¹´05月25日

垃圾回收 GC

  • GC: Garbage Collection
  • 垃圾: 需要回收的对象, 未被引用的对象;
  • æ ¹: 判断对象是否被引用的起始点, 基本上是将变量和运行栈空间作为根;

标记清除法:

  1. 标记阶段(Mark phase): 从根开始递归式的标记出 被引用对象 和 未引用对象(垃圾);
  2. 清除阶段(Sweep phase): 扫描全部对象, 清除 未引用对象(垃圾), 重置 被引用对象 的标记, 用于下一次GC;

标记清除法的缺点是, 如果有大量对象并且其中只有小部分存活的情况下, 扫描垃圾对象十分耗时, 复制收集法则克服了这一缺点.

复制收集法:

  1. 在旧对象所在的空间外, 开辟出一块 新空间;
  2. 将 被引用的对象 复制到新空间;
  3. 清空 旧空间;

引用计数法:

  1. 在每个对象中保存该对象的引用计数, 当引用发生增减时对计数进行更新;
  2. 清空计数为 0 的垃圾对象;

缺点:

  1. 引用计数法无法释放循环引用的对象;
  2. 对引用的增减必须完全正确, 否则会引起很难排查的内存错误;
  3. 不适合并行处理, 多线程同时对引用计数进行增减的话, 有可能会产生计数不一致的问题;

分代回收法:

  1. 按照对象生成时间分代, 刚刚生成不久的对象标记为 新生代, 存活很久的对象标记为 老生代
  2. 小回收: 只扫描 新生代对象, 将扫描后依旧存活的对象标记为 老生代;
  3. 一次性扫描 老生代;

增量回收法:

  1. 在程序运行的同时进行 GC 操作, 渐进式的 GC 操作;
  2. 此方法可以控制 GC 的耗时, 适用于实时性要求高的场景;

并行回收法:

  1. 充分利用多 CPU 的性能, 在程序运行的同时进行 GC 操作

闭包

什么是闭包?

  1. 起因: 变量脱离作用域后没有消失, 在某个地方继续存活着;
  2. 表现: 函数内返回函数, 外部函数可以引用内部函数的局部变量, 此时内部函数叫做闭包函数;

闭包的用途?

  1. 封装私有变量, "穷人版的面向对象", 闭包和对象是同一事物的正反两面;
  2. 存储变量;

闭包的缺点?

  1. 闭包函数中的变量存储在内存中, 无法被回收, 滥用闭包会引起内存泄漏

闭包和对象:

  1. 闭包和对象都可以实现私有变量
  2. 二者可以互相模拟

    • 没有闭包的编程语言可以用对象来模拟
    • 没有对象的编程语言可以用闭包来模拟

闭包和对象是同一事物的正反两面 示例:

// 闭包实现私有变量
function outer() {
    var one = 1;
    var two = 2;

    return function inner(){
        return one + two;
    };
}

// 对象实现私有变量
var obj = {
    one: 1,
    two: 2
};

泛型

拥有静态类型的语言, 必然需要带参数的类型 (泛型).

不用泛型的示例:

function identity(arg: number): number {
    return arg;
}

或者用 any 类型:

function identity(arg: any): any {
    return arg;
}

用泛型, T 用于捕获输入的类型, 返回 T 表示此方法输入和输入类型一致:

function identity<T>(arg: T): T {
    return arg;
}

(完)