计算机存储器是计算机系统中最为核心的部分之一,它是计算机系统中的数据存储、读写操作的场所,使用了如 DRAM、SRAM 等芯片作为存储媒介,是计算机系统中最快速的部分之一。以下从不同的方面来阐述计算机存储器:
一、内存分类
内存通常分为随机存储器(RAM)和只读存储器(ROM)。RAM 是一种易失性存储器,存放的内容需要经过电源供电才能保留,常见的有动态随机存储器(DRAM)和静态随机存储器(SRAM)。DRAM 存储单元需要定期刷新数据才能保持,而 SRAM 存储单元不需要定期刷新。ROM 是一种非易失性存储器,存放的内容不需要经过电源供电就可以保存,常见的有只读存储器(ROM)、可编程只读存储器(PROM)、可擦写可编程只读存储器(EPROM)和电可擦可编程只读存储器(EEPROM)。
// C 语言代码示例:使用指针动态分配内存
#include <stdio.h>
#include <stdlib.h>
int main() {
int* ptr; // 定义一个指向整型数据的指针
int num = 5; // 定义一个整型变量
ptr = (int*)malloc(num * sizeof(int)); // 动态分配内存
if (ptr == NULL) {
printf("动态分配内存失败!");
exit(0);
}
for (int i = 0; i < num; i++) {
*(ptr + i) = i; // 给指针所指向的内存赋值
}
for (int i = 0; i < num; i++) {
printf("%d ", *(ptr + i)); // 输出指针所指向的内存
}
free(ptr); // 释放内存
return 0;
}
二、内存寻址
内存寻址指的是CPU对内存单元进行访问的方式,在程序运行时,CPU 访问内存的地址是由程序中指定的内存地址决定的。CPU 提供了一组地址总线,根据地址总线的数位规定,计算机的内存寻址空间大小也就被确定下来。在现代计算机中,CPU 的地址总线宽度一般为 32 位或 64 位,因此可以寻址的内存空间大小为 2^32个字节或2^64个字节。
// C 语言代码示例:从指定地址的内存单元读取数据
#include <stdio.h>
#include <stdlib.h>
int main() {
char* data = (char*)malloc(1 * sizeof(char));
if (data == NULL) {
printf("动态分配内存失败!");
exit(0);
}
long address = 0x7fff5fbff718; // 一个 64 位地址
*data = *(char*)address; // 从指定地址的内存单元读取一个字节的数据
printf("读取的数据为:%cn", *data);
free(data); // 释放内存
return 0;
}
三、内存映射
内存映射指的是将计算机外部设备的状态映射到计算机内存空间的技术。内存映射使得在编程中可以像读写内存单元一样来读写外部设备的状态,极大地简化了编程。例如,在 Linux 系统中,可以将硬盘上的文件映射到内存中,以便更快地进行读写操作。
// C 语言代码示例:使用内存映射文件进行读写操作
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
int fd = open("file.txt", O_RDWR); // 打开文件
if (fd == -1) {
printf("打开文件失败!");
exit(0);
}
struct stat sb; // stat 结构体
if (fstat(fd, &sb) == -1) { // 获取文件状态
printf("获取文件状态失败!");
exit(0);
}
char* addr = (char*)mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // 映射文件到内存
if (addr == MAP_FAILED) {
printf("映射文件到内存失败!");
exit(0);
}
char str[] = "Hello, world!"; // 字符串
int len = sizeof(str) / sizeof(*str); // 确定字符串长度
for (int i = 0; i < len; i++) {
*(addr + i) = *(str + i); // 写入字符串到内存
}
printf("%sn", addr); // 从内存读取字符串
munmap(addr, sb.st_size); // 取消内存映射
close(fd); // 关闭文件
return 0;
}
四、内存管理
内存管理是指对计算机内存的使用、分配、释放进行有效控制,以提高内存的使用效率和程序的健壮性。常见的内存管理策略有静态分配、动态分配、内存池和垃圾回收等。在使用动态分配内存时,程序员需要自行分配和释放内存,如果出现错误可能会造成内存泄漏或内存损坏等问题。内存池技术可以对内存进行缓存,实现快速的内存分配和回收,从而提高程序的性能和稳定性。垃圾回收技术可以自动地回收不再使用的内存资源,减少了程序员的工作量,但会造成一定的程序性能损失。
// C 语言代码示例:使用内存池分配和释放内存
#include <stdio.h>
#include <stdlib.h>
#define MAX_NUM 10 // 内存池大小
void* my_malloc(int size); // 内存分配函数
void my_free(void* ptr); // 内存释放函数
int main() {
int* ptr1 = (int*)my_malloc(sizeof(int)); // 分配内存
*ptr1 = 10; // 给内存赋值
printf("%dn", *ptr1); // 输出内存中的数据
int* ptr2 = (int*)my_malloc(sizeof(int)); // 内存不足时,再次分配内存
*ptr2 = 20; // 给内存赋值
printf("%dn", *ptr2); // 输出内存中的数据
my_free(ptr1); // 释放已经使用的内存
my_free(ptr2);
return 0;
}
void* my_malloc(int size) {
static char memory[MAX_NUM * sizeof(int)]; // 内存池
static int start = 0; // 下一个可用块的索引
int block_num = MAX_NUM - start; // 当前还剩下的内存块数量
if (block_num * sizeof(int) < size) {
printf("内存分配失败!");
exit(0);
}
void* ptr = (void*)(memory + start * sizeof(int)); // 分配内存并返回
start += size / sizeof(int);
return ptr;
}
void my_free(void* ptr) {
// 略去释放内存的具体实现
}
五、内存保护
内存保护是指通过操作系统以及硬件的支持,为了避免程序出现内存错误而采取的一系列措施。内存保护可以限制程序的访问内存的范围,防止程序访问非法的内存区域,以及检测访问内存的错误。在计算机系统中,可以通过硬件支持的内存保护机制(如MMU)来实现,可以设置预设参数对内存进行保护,防止程序访问到系统内核区域、只读内存区域、未使用内存区域等。
// C 语言代码示例:在 Linux 系统中使用 mprotect 系统调用保护内存
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
int main() {
int* ptr = (int*)malloc(1 * sizeof(int));
if (ptr == NULL) {
printf("分配内存失败!");
exit(0);
}
// 将内存区设置为只读
if (mprotect(ptr, sizeof(int), PROT_READ) == -1) {
printf("设置内存保护失败!");
exit(0);
}
*ptr = 5; // 写入数据
printf("%dn", *ptr); // 读取数据
free(ptr); // 释放内存
return 0;
}