青训营笔记 | day5 学习记录

63 阅读3分钟

自动内存管理

自动内存管理的基本概念

动态内存

程序根据自身的运行需要对内存进行的一个申请(像在 C 语言中我们就可以通过 mlloc()/alloc() 进行内存的分配)

自动内存管理(有程序的运行时进行管理,即垃圾回收)

1. 不需要手动进行内存的管理,我们就可以专注与业务代码的实现
2. 保证内存的使用的正确与安全,避免出现(double-free problem,use-after-free problem)的情况,可能会造成安全问题以及程序崩溃

主要的工作

1. 为新的对象分配空间
2. 寻找正在使用的对象
3. free 已经消亡对象的空间

方式

1. Tracing garbage collection 
2. Generational GC
3. Reference counting

Some Definition for Automatic Memory Management

  • Mutator

    • 业务线程,分配新对象,修改对象指向关系
  • Collector

    • GC线程,找到存活对象,free 回收死亡对象的空间
  • Serial GC

    • 只存在一个 collecor
  • Parallerl GC

    • 支持多个 collectors 同时进行回收的 GC 算法
  • Concurrent GC

    • mutator(s) & collector(s) 同时运行(需要知道对象的指向关系的转变,已标记对象指向的对象也需要进行标记)

评价 GC 算法的一些标准

  • Safety(安全性)
    • 不能回收存活的对象
    • 基本要求
  • Throughput(吞吐率)
    • 1GC时间/程序执行总时间1 - GC 时间 / 程序执行总时间
    • 在 GC 上花费的时间
  • Pause time(暂停时间)
    • Stop the world(STW)
    • 业务是否感知
  • Space overhead(内存开销)
    • GC 元数据开销

常见的两种 GC 技术

Tracing garbage collection(追踪垃圾回收)
  • 条件: 指针引用关系不可达
  • 步骤
    1. 标记根对象
      1. 静态变量
      2. 全局常量
      3. 常量
      4. 线程栈
      5. ...
    2. 标记: 找到可达的对象
      1. 求指针对象指向关系的传递闭包
      2. 从根对象出发,寻找可达的对象
    3. 清理: 所有不可达对象
      1. 将存活对象拷贝到另外的区域(copying GC)
      2. 将死亡对象空间标记为"可分配的"(Mark-sweep GC)
      3. 对对象进行移动整理(Mark-compact GC)

Note: 对于一些声明周期不同的对象,可能采取不同的标记和清理策略

Generational GC(分代 GC)

1. 分代假说(Generationalhyupothesis): most objects die young
2. Intuition: 一些对象分配出来后很快就不再使用
3. 对象有年龄(经历过 GC 的次数)
4. 目的: 对于年轻或者是老的对象采取不同的 GC 策略, 降低整体内存的开销
5. 不同的年龄对象处于 Heap 的不同区域(Young/Old Generation)
  1. Young generation
    1. 常规对象分配
    2. 存活对象少,可以采用 copying collection
    3. GC 吞吐率高
  2. Old generation
    1. 对象一直存活,反复复制会使开销较大
    2. 可以采用 mark-sweep collection
Reference counting(引用计数)
1. 每个对象有一个相关联的引用数目
2. 对象存活的条件: Reference counts > 0

优点

1. 内存管理的操作被平摊到程序执行过程中
2. 内存管理不需要了解 runtime 的实现细节(C++ 智能指针 smart pointer)

缺点

1. 维护计数开销大(需要使用原子操作保证计数的原子性和可见性)
2. 对于环形的数据结构无法进行回收(当然还有其它方式对它进行回收)
3. 内存开销: 每一个对象引入额外的内存空间用于引用数目
4. 回收内存可能会造成暂停(当一个节点下挂着许多节点时)