指令集以及栈堆介绍

目录

1. 指令集分类

1.1. CISC

1.2. RISC

1.3. 两者区别

2. 栈和堆的区别

2.1. 栈介绍

2.1.1. 生成机制

2.1.2. 触发场景

2.1.3. 特点

2.2. 堆介绍

2.2.1. 生成机制

2.2.2. 触发场景

2.2.2.1. C语言

2.2.2.2. C++

2.2.2.3. 栈溢出/堆内存泄

2.2.3. 两者对比

3. 引用来源


1. 指令集分类

指令集为一套操作系统的指令集合,以及相关规范体系。是一种上层定义,汇编就是其具体的体现和实现。指令集分为以下两类:

  • CISC 复杂指令集,以 x86 为代表(x86 在 PC 服务器领域具有统治地位)
  • RISC 精简指令集,以 ARM MIPS 为代表(ARM 统治了手机和平板领域,MIPS 常用语手机、电脑之外的其他电子设备)

1.1. CISC

计算机编程很麻烦,例如用纸带打孔输入,因此计算机的设计者就考虑将 CPU 做的复杂一点,以简化这种本来就很麻烦的编程。因此有了 CISC 复杂指令集。x86 就是其中的典型代表,x86 的特点是:

  • 指令向下兼容(这是其商业成功的重要因素之一!!!),缺点就是会让指令集越来越大、越来越复杂,功耗也更大(因此不适用于低功耗设备)
  • 变长指令(MIPS 是等长的,只有 32 位),优点是节省空间、扩展性好,缺点是译码复杂
  • 多种寻址方式
  • 通用寄存器个数有限,x86-32 只有 8 个通用寄存器,x86-64 也只有 16 个寄存器
  • 指令中,最多能有一个操作数在内存中,其他的操作数必须是立即数或者寄存器

1.2. RISC

历史原因,RISC 是 80 年代初发明的,那时整个计算机生态系统已经形成,编译器能力增强,就不需要 CPU 对外暴露过度复杂的指令集,因此有了 RISC 精简指令集。MIPS ARM 是 RISC 的代表,RISC 指令集特点是:

  • 只关注一些简单常用的指令,因此简单轻量、高性能、功耗低
  • 那些不常用的复杂指令,就依赖于编译器(即用软件来实现,而不是依赖于硬件的复杂指令),那时编译器已经比较强大

MIPS 特点:

  • 以寄存器为中心。一出手就是 32 位(即寄存器是 32 位的),而且有 32 个通用寄存器
  • 只有 loadstore 指令可以访问内存,其他指令只能操作寄存器和立即数(以寄存器为中心嘛)
  • 指令格式规范,长度一致(32 位),导致空间利用率不高,但是译码效率高
  • 寻址方式非常简单

ARM 指令集特点:

  • 大多数指令支持“条件执行”模式,能使得代码比较精简
  • 具有 16 位压缩指令集,低功耗、低存储场景下很适用(ARM 在移动领域取得很大的成功,如 iphone 上的 A 系列处理器)

1.3. 两者区别

(1)指令系统。RISC主要设计经常使用的指令,让它们有简单高效的特色,对不常用的功能,常通过组合指令来完成,实现特殊功能的效率较低;CISC指令比较丰富,有专用指令来完成特殊功能,处理特殊任务的效率较高;

(2)对主存操作的限制。RISC对存储器操作有限制,使控制简单化;CISC机器存储器操作指令多,操作直接;

(3)编程的方便性。CISC对于汇编语言来说相对容易,可选指令多;RISC的汇编语言更困难

(4)寻址方式:RISC尽可能使用较少的寻址方式;CISC提倡通过丰富的寻址方式为用户编程提供更大的灵活性

(5)指令格式。RISC追求指令格式的规整性,一般使用等长的指令字来设计所有的指令格式;CISC指令格式因为要考虑更多的寻址方式可能引起的指令长度的变化等,设计起来相对要复杂;

(6)控制器设计。由于RISC指令格式规整、指令执行时间上的差异性很小,导致对应的CPU的控制器设计要简单,而且很多RISC可以使用硬布线方式(组合逻辑)高效实现;CISC的指令系统对应的控制信号复杂,大多采用微程序控制器方式。不管RISC和CISC都采用流水线技术提高效率。

2. 栈和堆的区别

2.1. 栈介绍

2.1.1. 生成机制

  • 栈内存由编译器自动管理,通过函数调用分配和释放。
  • 函数调用时,栈帧被压入栈,包含局部变量、参数和返回地址。
  • 函数返回时,栈帧弹出,内存自动释放。

2.1.2. 触发场景

  • 函数调用:每个函数调用生成新栈帧。
  • 局部变量:非静态、非动态的变量在栈上分配。

栈由操作系统自动分配释放 ,用于存放函数的参数值、局部变量等,其操作方式类似于数据结构中的栈。参考如下代码。

void example() {
    int a;          // 栈上分配
    char buffer[64];// 栈上分配
}

其中函数中定义的局部变量按照先后定义的顺序依次压入栈中,也就是说相邻变量的地址之间不会存在其它变量。栈的内存地址生长方向与堆相反,由高到底,所以后定义的变量地址低于先定义的变量,比如上面代码中变量 s 的地址小于变量 b 的地址,p2 地址小于 s 的地址。栈中存储的数据的生命周期随着函数的执行完成而结束。

2.1.3. 特点

  • 分配/释放速度快,但容量有限(易栈溢出)。
  • 无需手动管理,由编译器控制生命周期。

2.2. 堆介绍

2.2.1. 生成机制

  • 堆内存需显式申请和释放,生命周期由程序员控制。
  • 通过动态内存管理函数手动操作。

2.2.2. 触发场景

2.2.2.1. C语言
  • malloc:分配未初始化的内存。
  • calloc:分配并初始化为零的内存。
  • realloc:调整已分配内存的大小。
  • free:释放内存。
int* p = (int*)malloc(sizeof(int)); // 堆分配
free(p);                            // 释放
2.2.2.2. C++
  • new:分配内存并调用构造函数。
  • delete:调用析构函数并释放内存。
  • new[]delete[]:处理数组。
int* arr = new int[10]; // 堆分配数组
delete[] arr;            // 释放

堆的内存地址生长方向与栈相反,由低到高,但需要注意的是,后申请的内存空间并不一定在先申请的内存空间的后面,即 p2 指向的地址并不一定大于 p1 所指向的内存地址,原因是先申请的内存空间一旦被释放,后申请的内存空间则会利用先前被释放的内存,从而导致先后分配的内存空间在地址上不存在先后关系。堆中存储的数据若未释放,则其生命周期等同于程序的生命周期。

int main() {
	// C 中用 malloc() 函数申请
	char* p1 = (char *)malloc(10);
	cout<<(int*)p1<<endl;		//输出:00000000003BA0C0
	
	// 用 free() 函数释放
	free(p1);
   
	// C++ 中用 new 运算符申请
	char* p2 = new char[10];
	cout << (int*)p2 << endl;		//输出:00000000003BA0C0
	
	// 用 delete 运算符释放
	delete[] p2;
}

操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆节点,然后将该节点从空闲节点链表中删除,并将该节点的空间分配给程序。另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确地释放本内存空间。由于找到的堆节点的大小不一定正好等于申请的大小,系统会自动地将多余的那部分重新放入空闲链表。

2.2.2.3. 栈溢出/堆内存泄

栈溢出:

  • 避免过深递归或过大局部变量(如大数组)。
void risky() {
    int huge[1000000]; // 可能栈溢出
}

栈溢出危害为,通过相关栈溢出漏洞,修改相关返回值,进而修改并植入相关恶意代码。简单的参考文章如下:

使用vc6.0探讨栈溢出对代码进行攻击_c栈溢出攻击代码-CSDN博客

堆内存泄漏:

  • 确保每次 malloc/new 后都有对应的 free/delete
  • 使用C++智能指针(如 std::unique_ptrstd::shared_ptr)自动管理堆内存。

野指针:

  • 释放内存后,将指针置空
delete ptr;
ptr = nullptr; // 避免悬空指针

2.2.3. 两者对比

  • :函数调用和局部变量自动生成,高效但容量有限。
  • :通过 malloc/new 显式生成,灵活但需手动管理。
  • 核心函数:栈由编译器隐式处理;堆依赖 malloc/free(C)或 new/delete(C++)。

3. 引用来源

[网络工程师]-计算机硬件基础-指令集CISC/RISC_cisc计算机使用的寻址方式简单,指令条数少-CSDN博客

汇编语言学习精华-CSDN博客

堆与栈详解-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

B10SS0MS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值