聊聊内存(Memory)
2020-07-26
0. 前言
每台电脑都有操作系统,比如 Windows 系统,Mac OS 等。
对于操作系统而言,最重要的就是管理计算机的资源,包括(但不限于):
- 进程管理(Process Management)
- 内存管理(Memory Management)
- 文件管理(File Management)
- 设备管理(Device Management)
今天我们聊的是内存管理。
内存是什么呢?
首先我们要知道,计算机储存数据的方式有两种:
- 内存
- 外存(如硬盘、USB 等储存设备,使用时需要调入内存)
所以,内存就是计算机储存数据的方式之一。
1. 内存分类
内存又可以分为:
- RAM(包括 Cache)
- ROM
PS:Cache(缓存)在 CPU 里面讲过。
价格:Cache > RAM > ROM
速度:Cache > RAM > ROM
和 CPU 的距离:Cache < RAM < ROM
RAM 和 ROM 的区别
RAM (Ramdom Access Memory) :随机存取存储器
ROM (Read Only Memory):只读存储器
RAM(随机存取存储器) | ROM(只读存储器) | |
---|---|---|
断电后 | 数据丢失 | 数据还在 |
读数据 | √ | √ |
写数据 | √ | × |
大小(size) | 比较大 | 比较小 |
用途 | CPU cache,内存 | 存储与设备相关的信息;跟 BIOS(Basic Input/Output System) 相关 |
ROM 是在设备出厂的时候就写好的;
当你启动计算机的时候,ROM 是首先运行的,由于里面包含着一些重要的固件信息,一般来说是不会修改的。
PS: 目前有提议用 UEFI (Unified Extensible Fireware Interface) 来取代 BIOS。
Memory 的定义
一般来说,Memory 指的是 RAM。
2. Data - Stack vs Heap vs Queue
Stack(栈) vs Queue(队列)
之前我们在 Data Type 里面讲过 Stack 和 Queue 的区别,Stack 是 FILO,Queue 是 FIFO。
Stack 和 Queue 都是 Abstract Data Type。
那么 Heap 又是什么呢?
Heap(堆)
其实 Heap 是一种数据结构(Data Structure),而我们知道,数据结构是用来实现数据类型的。
那么 Heap 是什么数据类型呢?
答案是:Priority Queue,也就是 Queue 的一种特殊类型。
Priority Queue
这种 Queue 和我们之前讨论的 FIFO 有一个不同之处,那就是每个排队的成员都增加了一个叫做优先级(priority)的属性。
Queue:1 号,2 号,3 号,4 号(1 号先进,1 号先出)
Priority Queue:1 号(优先级=1),2 号(优先级=5),3 号(优先级=3),4 号(优先级=2)
在这个带有优先级的 Queue 里面,优先级越高,越先出去。
所以 2 号先出去,接着是 3 号,4 号,1 号。
在这种数据类型中,顺序是由优先级决定的。
Heap 就是 Priority Queue 的实现形式。
3. Memory - Stack vs Heap
这里我必须吐槽一下,memory 里面的 stack 和 heap 其实跟 data 里面讲的 stack 和 heap 是不一样的!!!!!(虽然名字一样
对于新手小白来说,这些名词简直太容易混淆了(说的就是我)。
在咨询了各路大神之后,发现:
Memory Stack(内存栈)和 Memory Heap(内存堆)跟我们之前提到的数据结构(Heap)、数据类型(Stack)没有直接关系!!!
内存分配
内存分配有两种方式:静态内存分配(Static Memory Allocation)和动态内存分配(Dynamic Memory Allocation)。
Stack Memory 和 Heap Memory 是内存的不同区域,静态内存分配使用的是 Stack Memory,动态内存分配使用的是 Heap Memory。
Stack Memory 依旧保持着 FILO (先进后出)的特性,但是 Heap Memory 就跟我们之前说的 Priority Queue 没有半毛钱关系了。
静态内存和动态内存有什么区别?
Difference Between Static and Dynamic Memory Allocation > 动态内存与静态内存有何优劣?
静态内存 | 动态内存 | |
---|---|---|
内存是否可以变 | 固定大小,分配好了就不能变 | 分配好了也可以变 |
内存创建时间 | 程序编译时 | 程序调入和执行时 |
内存创建者 | 编译器 | 程序员(比如 C 语言的 malloc, calloc 函数,C# 里面的 new) |
内存回收者 | 操作系统 | 程序员或编程语言自带的 Garbage Collection 功能 |
内存速度 | 很快 | 比静态内存慢 |
静态内存和动态内存的创建时间和创建者是不同的,分别对应程序生命周期的两个阶段(编译、运行)。
静态内存:静态变量和自动变量
静态内存分配的是静态变量(static variable)所占用的存储空间,这个空间在程序运行之前就可以被计算出来。
静态变量是程序里面声明的 static 变量或者 global 变量。
// 创建一个静态变量(static or global variable)
static int number = 1;
而自动变量(automatic variable)往往也被称为 Local variable,这些变量离开了 scope(作用域)之后就不需要了。这些变量是通过 stack-based memory(也就是静态内存)来分配的。
// 创建一个自动变量
void Method()
{
int localVariable = 1;
}
所以,静态变量和自动变量都是通过静态内存来分配的。
PS: 静态内存如果用完了(比如你写了个 infinite for loop),报错是:StackOverflowException。
动态内存:引用类型
动态内存里面放的是 Reference Type。
这里拿我之前的 C# Types 文章配图来举例,我们可以看到,Reference Type 的实际 Object 是存放在 Heap Memory 里面的,只有 Object Reference 是存放在 Stack Memory 里面的。
PS: 动态内存如果用完了(比如你没有好好回收资源造成了 memory leak ),报错是:OutOfMemoryException。
In computer programming, a static variable is a variable that has been allocated “statically”, meaning that its lifetime is the entire run of the program.
The storage of shorter-lived automatic variables is stack allocated and deallocated on the call stack .
The storage of objects is dynamically allocated and deallocated in heap memory.
图解
4. 结语
在这篇文章里面,我们讲了:
- 内存的分类(RAM, ROM)
- CPU 里面的 Cache 属于 RAM
- RAM 和 ROM 的区别(RAM 能读能写, ROM 只读不写)
- 重点区分了在不同语境里面的 Stack 和 Heap(数据语境和内存语境是完全不同的哦!!)
- Heap 在数据语境里面 = Priority Queue 这种 ADT 的实现形式
- Heap 在内存语境里面跟 Queue 没有半毛钱关系……
- Stack 在两种语境里面都有 FILO 的特征
- Call Stack 是 Stack ADT 的一种实现形式
- 内存语境下,Stack 和 Heap 分别对应不同的内存分配方式(static 和 dynamic)
- 静态内存分配完了就不能改,存的是静态变量和自动变量,由编译器和 CPU 管理,在程序编译期间分配
- 动态内存分配完了也能改,存的是引用类型,由程序员和编程语言的特性来管理,在程序运行期间分配