-
托管语言(managed language)
-
托管运行时系统(managed run-time system)
-
动态内存分配(allocation)
- 存在于堆(heap)
- 动态
- 递归
- 闭包
- 函数式
- 通过*引用(reference)*进行访问
- 通常,引用即指向对象的指针(pointer)
- 对象在内存中的地址
- 间接访问时,则使用句柄(handle)
- 好处在于:迁移某一对象时,避免通过程序改变这个对象或句柄的所有引用
- 通常,引用即指向对象的指针(pointer)
- 而非栈(stack)
- 程序的活动记录(activation record)、栈帧(stack frame)
- 或者静态区(statically)
- 编译器或者连接期就可以确定范围的存储区域
- 存在于堆(heap)
内存管理的几种常见策略:
- 显式释放(explicit deallocation)策略
- 手动管理
- C
free
- C++
delete
- C
- 基于引用计数
- 追踪式垃圾回收器
- 风险
- 悬挂指针(dangling pointer)
- 使用*肥指针(fat pointer)*检测
- 将指针目标对象的版本号作为指针本身的一部分
- 使用*肥指针(fat pointer)*检测
- 内存泄露(memory leak)
- 并发问题
- 死锁(deadlock)
- 活锁(livelock)
- ABA问题(ABA probleam)
- 悬挂指针(dangling pointer)
- 手动管理
规避内存管理中,存活性问题的几种思路:
- 栈上分配
- 创建对象的函数返回之后,栈的弹出(pop)操作会自动将对象释放
- 值传递
- 对象池(pool of object)
- 程序某个阶段完成之后,池中的对象整体全部释放
- 特殊指针、模板
- 堆指针操作进行重载(overload)
- 智能指针(smart pointer),兼容性问题
- unique_ptr
- 严格的所有权控制语义
- 指针被摧毁时,其目标对象将自动得到释放
- shared_ptr
- 基于引用计数
- 无法处理自引用(环状引用)的数据结构
- 只适用于管理:
- 数据块非常大
- 引用关系变更较少
- 堆指针操作进行重载(overload)
自动动态内存管理
- 垃圾回收(garbage collection,GC)
- 追踪式回收(tracing collection)
- 垃圾
- 不再使用的对象
- 只有回收器可以释放对象
- 避免*二次释放(double-freeing)*问题
- 回收器掌握堆中对象的全局信息以及所有可能访问堆中对象的线程信息
- 因此,可以决定任意对象是否需要回收
垃圾回收算法的考量指标:
- 安全性
- 吞吐量
- 完整性
- 及时性
- 停顿时间
- 空间开销
- 针对特定语言的优化
- 可扩展性与可移植性
赋值器、回收器性能需要平衡:
- 最小赋值器使用率(minimum mutator utilization,MMU)
- 界限赋值器使用率(bounded mutator utilization,BMU)
实时基准检测,自适应策略
垃圾回收算法基本概念:
- 堆
- 由一段或者几段连续内存组成的空间集合
- 内存颗粒(granule)
- 堆内存分配的最小单位
- 一般为一个字(word),或者一个双字(double-word)
- 取决于对齐(alignment)方式
- 内存块(chunk)
- 一组较大的连续内存颗粒
- 依据特定大小对齐的大块内存
- 内存单元(cell)
- 由数个连续颗粒组成的小内存块
- 通常用于内存的分配和释放
- 对象
- 应用程序分配的内存单元
- 通常是一段可寻址的连续字节或字的数组
- 内部被划分成多个槽(slot)或者域(field)
- 对象头
- 用一个头域(header field)来存放运行时系统会用到的元数据
- 对象图(object graph)
- 有向图(directed graph)
- 图的节点(node)是堆中的对象
- 有向边是对象之间的引用
- 边一般是从源节点(source node)或者根(root)指向目标节点(destination node)的引用
- 帧(frame)
- 一大段2^k大小的地址空间
- 空间(space)
- 由一系列(可能)不连续的内存块组成的集合
- 页(page)
- 由硬件以及操作系统的虚拟内存机制定义
- 高速缓存行(cache line)、高速缓存块(cache block)
- 由CPU的高速缓存(cache)
- 卡(card)
- 以2的整数次幂对齐的内存块
- 一般小于一页
- 通常与某些跨空间指针的方案有关
- 赋值器
- 执行应用代码
- 分配新的对象
- 修改对象之间的引用关系
- 改变堆中对象图的拓扑结构
- 回收器
- 执行垃圾回收代码
- 找到不可达对象并将其回收
- 执行垃圾回收代码
- 赋值器根
- 一个有限的指针集合
- 赋值器可以不经过其他对象直接访问这些指针
- 根对象(root object)
- 堆中直接由赋值器根所引用的对象
- 引用
- 通常是一个正规指针(canonical pointer)
- 指向对象头部(即对象首地址)
- 或者距头部有一定偏移量的地址
- 派生指针(derived pointer)
- 一般是在对象的正规指针的基础上增加一个偏移量而得到的指针
- 内部指针(interior pointer)
- 指向内部对象域的派生指针
- 通常是一个正规指针(canonical pointer)
- 域
- 可能会包含一些非引用的纯数据
- 地址
- 存活性
- 能被赋值器访问,则该对象存活
- 不论是否被使用
- 指针可达
- 分配器(allocator)
- 分配(allocate)
- 为某一对象保留底层的内存存储
- 释放(free)
- 将内存归还给分配器以便复用
- 分配(allocate)
- 赋值器读写操作
- 创建(New)
- 从堆分配器中获得一个新的堆对象
- 分配器返回新分配的对象首地址
- 读(Read)
- 指向对象的指针
- 待访问的域的索引号
- 写(Write)
- 引发内存存储
- 指向元对象的指针
- 待修改域的索引号
- 待存储的值(纯值或者指针)
- 使用屏障(barrier)
- 会同步或者异步的与回收器产生交互
- 读屏障(read barrier)
- 写屏障(write barriter)
- 创建(New)
- 原子操作
- 挂起赋值器
- 确保垃圾回收过程的原子性(atomically)
- 垃圾回收过程中赋值器不会访问堆中对象
- 挂起赋值器
- 集合
- set
- 存放不同元素的容器(元素两两不同)
- 集合中元素的数量称为基(cardinaliy),写作:|S|
- 多集合
- multiset
- 内部允许存在相同元素
- 某一元素出现的次数称为该元素的重数(multiplicity)
- 符号:[]
- 序列
- sequence
- 可重复,有顺序
- 符号:()
- 元组
- tuple
- 长度不变
- 符号:<>