当前位置: 首页 > news >正文

函数栈帧的创建和销毁(详解)

在这里插入图片描述

函数栈帧的创建和销毁

  • 🦖函数栈帧是什么?
  • 🦖函数栈帧的创建和销毁解析
    • 🐋栈是什么?
    • 🐋认识相关寄存器和汇编指令
    • 🐋解析函数栈帧的创建和销毁
      • 🐳预备知识
      • 🐳函数的调用堆栈
      • 🐳准备调试环境
      • 🐳转到反汇编
      • 🐳函数栈帧的创建
      • 🐳函数栈帧的销毁
  • 🦖结语

🦖函数栈帧是什么?

函数栈帧(stack frame)就是函数调用过程中在程序的调用栈(call stack)所开辟的空间,这些空间
是用来存放:

  • 函数参数和函数返回值
  • 临时变量(包括函数的非静态的局部变量以及编译器自动生产的其他临时变量)
  • 保存上下文信息(包括在函数调用前后需要保持不变的寄存器)

🦖函数栈帧的创建和销毁解析

🐋栈是什么?

  • 栈(stack)是现代计算机程序里最为重要的概念之一,几乎每一个程序都使用了栈,没有栈就没有函
    数,没有局部变量,也就没有我们如今看到的所有的计算机语言。
  • 在经典的计算机科学中,栈被定义为一种特殊的容器,用户可以将数据压入栈中(入栈,push),也可
    以将已经压入栈中的数据弹出(出栈,pop),但是栈这个容器必须遵守一条规则:先入栈的数据后出栈(First In Last Out, FIFO)。就像叠成一叠的书,先叠上去的书在最下面,因此要最后才能取出。
  • 在计算机系统中,栈是一个具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据
    从栈顶弹出。压栈操作使得栈增大,而弹出操作使得栈减小。
  • 在经典的操作系统中,栈总是向下增长(由高地址向低地址)的。
  • 在我们常见的i386或者x86-64下,栈顶由 esp 的寄存器进行定位的,而栈底由 ebp 的寄存器进行定位的。

🐋认识相关寄存器和汇编指令

相关寄存器

eax:通用寄存器,保留临时数据,常用于返回值
ebx:通用寄存器,保留临时数据
ebp:栈底寄存器
esp:栈顶寄存器
eip:指令寄存器,保存当前指令的下一条指令的地址

相关汇编指令

mov:数据转移指令
push:数据入栈,同时esp栈顶寄存器也要发生改变
pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变
sub:减法命令
add:加法命令
call:函数调用,1. 压入返回地址 2. 转入目标函数
jump:通过修改eip,转入目标函数,进行调用
ret:恢复返回地址,压入eip,类似pop eip命令

🐋解析函数栈帧的创建和销毁

🐳预备知识

  • 每一次函数调用,都要为本次函数调用开辟空间,就是函数栈帧的空间。
  • 这块空间的维护是使用了2个寄存器:esp和ebp,ebp记录的是栈底的地址,esp记录的是栈顶的地址。如图所示:
    在这里插入图片描述
  • 函数栈帧的创建和销毁过程,在不同的编译器上实现的方法大同小异。

🐳函数的调用堆栈

演示代码:

#include <stdio.h>int Add(int x, int y)
{int z = 0;z = x + y;return z;
} int main()
{int a = 3;int b = 5;int ret = 0;ret = Add(a, b);printf("%d\n", ret);return 0;
}

这段代码,我们在VS2019编译器上调试,进入Add函数后,我们就可以观察到函数的调用堆栈,如下图:
在这里插入图片描述
在这里插入图片描述

函数调用堆栈是反馈函数调用逻辑的,我们可以清晰的观察到,main函数调用之前,是由invoke_main函数来调用main函数。
在invoke_main函数之前的函数调用我们在本篇博客就暂时不考虑了。

我们可以确定, invoke_main 函数应该会有自己的栈帧, main 函数和 Add 函数也会维护自己的栈帧,每个函数栈帧都有自己的 ebp 和 esp 来维护栈帧空间。

🐳准备调试环境

为了让我们研究函数栈帧的过程足够清晰,不要太多干扰,我们可以关闭下面的选项,让汇编代码中排
除一些编译器附加的代码:

在这里插入图片描述

🐳转到反汇编

调试到main函数开始执行的第一行,右击鼠标转到反汇编。
注:VS编译器每次调试都会为程序重新分配内存,课件中的反汇编代码是一次调试代码过程中数据,每次调试略有差异。
在这里插入图片描述

🐳函数栈帧的创建

接下来我们就一行行拆解汇编代码

00BE1820 push ebp //把ebp寄存器中的值进行压栈,此时的ebp中存放的是invoke_main函数栈帧的ebp,esp-4
00BE1821 mov ebp,esp //move指令会把esp的值存放到ebp中,相当于产生了main函数的ebp,这个值就是invoke_main函数栈帧的esp
00BE1823 sub esp,0E4h //sub会让esp中的地址减去一个16进制数字0xe4,产生新的esp,//此时的esp是main函数栈帧的esp,此时结合上一条指令的ebp和当前的esp,ebp和esp之间维护了一个块栈空间,//这块栈空间就是为main函数开辟的,就是main函数的栈帧空间,//这一段空间中将存储main函数中的局部变量,临时数据已经调试信息等。
00BE1829 push ebx //将寄存器ebx的值压栈,esp-4
00BE182A push esi //将寄存器esi的值压栈,esp-4
00BE182B push edi //将寄存器edi的值压栈,esp-4
//上面3条指令保存了3个寄存器的值在栈区,这3个寄存器的在函数随后执行中可能会被修改,所以先保存寄存器原来的值,以便在退出函数时恢复。
//下面的代码是在初始化main函数的栈帧空间。
//1. 先把ebp-24h的地址,放在edi中
//2. 把9放在ecx中
//3. 把0xCCCCCCCC放在eax中
//4. 将从edp-0x2h到ebp这一段的内存的每个字节都初始化为0xCC
00BE182C lea edi,[ebp-24h]
00BE182F mov ecx,9
00BE1834 mov eax,0CCCCCCCCh
00BE1839 rep stos dword ptr es:[edi]

上面的这段代码最后4句,等价于下面的伪代码:

edi = ebp-0x24;
ecx = 9;
eax = 0xCCCCCCCC;
for(; ecx = 0; --ecx,edi+=4)
{*(int*)edi = eax;
}

在这里插入图片描述
小知识:烫烫烫~

在这里插入图片描述

之所以上面的程序输出“烫”这么一个奇怪的字,是因为main函数调用时,在栈区开辟的空间的其中每一个字节都被初始化为0xCC,而arr数组是一个未初始化的数组,恰好在这块空间上创建的,0xCCCC(两个连续排列的0xCC)的汉字编码就是“烫”,所以0xCCCC被当作文本就是“烫”。

接下来我们再分析main函数中的核心代码:

int a = 3;
00BE183B mov dword ptr [ebp-8],3 //将3存储到ebp-8的地址处,ebp-8的位置其实就是a变量
int b = 5;
00BE1842 mov dword ptr [ebp-14h],5 //将5存储到ebp-14h的地址处,ebp-14h的位置其实是b变量
int ret = 0;
00BE1849 mov dword ptr [ebp-20h],0 //将0存储到ebp-20h的地址处,ebp-20h的位置其实是ret变量
//以上汇编代码表示的变量a,b,ret的创建和初始化,这就是局部的变量的创建和初始化
//其实是局部变量的创建时在局部变量所在函数的栈帧空间中创建的
//调用Add函数
ret = Add(a, b);
//调用Add函数时的传参
//其实传参就是把参数push到栈帧空间中
00BE1850 mov eax,dword ptr [ebp-14h] //传递b,将ebp-14h处放的5放在eax寄存器中 
00BE1853 push eax //将eax的值压栈,esp-4
00BE1854 mov ecx,dword ptr [ebp-8] //传递a,将ebp-8处放的3放在ecx寄存器中
00BE1857 push ecx //将ecx的值压栈,esp-4
//跳转调用函数
00BE1858 call 00BE10B4
00BE185D add esp,8
00BE1860 mov dword ptr [ebp-20h],eax

在这里插入图片描述
Add函数的传参

//调用Add函数
ret = Add(a, b);
//调用Add函数时的传参
//其实传参就是把参数push到栈帧空间中,这里就是函数传参
00BE1850 mov eax,dword ptr [ebp-14h] //传递b,将ebp-14h处放的5放在eax寄存器中
00BE1853 push eax //将eax的值压栈,esp-4
00BE1854 mov ecx,dword ptr [ebp-8] //传递a,将ebp-8处放的3放在ecx寄存器中
00BE1857 push ecx //将ecx的值压栈,esp-4
//跳转调用函数
00BE1858 call 00BE10B4
00BE185D add esp,8
00BE1860 mov dword ptr [ebp-20h],eax

在这里插入图片描述
函数调用过程

//跳转调用函数
00BE1858 call 00BE10B4
00BE185D add esp,8
00BE1860 mov dword ptr [ebp-20h],eax

call 指令是要执行函数调用逻辑的,在执行call指令之前先会把call指令的下一条指令的地址进行压栈操作,这个操作是为了解决当函数调用结束后要回到call指令的下一条指令的地方,继续往后执行。
在这里插入图片描述
当我们跳转到Add函数,就要开始观察Add函数的反汇编代码了。

int Add(int x, int y)
{ 
00BE1760 push ebp //将main函数栈帧的ebp保存,esp-4
00BE1761 mov ebp,esp //将main函数的esp赋值给新的ebp,ebp现在是Add函数的ebp
00BE1763 sub esp,0CCh //给esp-0xCC,求出Add函数的esp
00BE1769 push ebx //将ebx的值压栈,esp-4
00BE176A push esi //将esi的值压栈,esp-4
00BE176B push edi //将edi的值压栈,esp-4int z = 0;
00BE176C mov dword ptr [ebp-8],0 //将0放在ebp-8的地址处,其实就是创建zz = x + y;//接下来计算的是x+y,结果保存到z中
00BE1773 mov eax,dword ptr [ebp+8] //将ebp+8地址处的数字存储到eax中
00BE1776 add eax,dword ptr [ebp+0Ch] //将ebp+12地址处的数字加到eax寄存中
00BE1779 mov dword ptr [ebp-8],eax //将eax的结果保存到ebp-8的地址处,其实就是放到z中return z;
00BE177C mov eax,dword ptr [ebp-8] //将ebp-8地址处的值放在eax中,其实就是把z的值存储到eax寄存器中,这里是想通过eax寄存器带回计算的结果,做函数的返回值。
} 
00BE177F pop edi
00BE1780 pop esi
00BE1781 pop ebx
00BE1782 mov esp,ebp
00BE1784 pop ebp
00BE1785 ret

代码执行到Add函数的时候,就要开始创建Add函数的栈帧空间了。

在Add函数中创建栈帧的方法和在main函数中是相似的,在栈帧空间的大小上略有差异而已。

  • 将main函数的ebp压栈
  • 计算新的ebp和esp
  • 将ebx,esi,edi寄存器的值保存
  • 计算求和,在计算求和的时候,我们是通过ebp中的地址进行偏移访问到了函数调用前压栈进去的参数,这就是形参访问。
  • 将求出的和放在eax寄存器中准备带回

在这里插入图片描述
图片中的 a’ 和 b’ 其实就是 Add 函数的形参 x , y 。这里的分析很好的说明了函数的传参过程,以及函数在进行值传递调用的时候,形参其实是实参的一份拷贝。对形参的修改不会影响实参。

🐳函数栈帧的销毁

当函数调用要结束返回的时候,前面创建的函数栈帧也开始销毁。

00BE177F pop edi //在栈顶弹出一个值,存放到edi中,esp+4
00BE1780 pop esi //在栈顶弹出一个值,存放到esi中,esp+4
00BE1781 pop ebx //在栈顶弹出一个值,存放到ebx中,esp+4
00BE1782 mov esp,ebp //再将Add函数的ebp的值赋值给esp,相当于回收了Add函数的栈帧空间
00BE1784 pop ebp //弹出栈顶的值存放到ebp,栈顶此时的值恰好就是main函数的ebp,esp+4,//此时恢复了main函数的栈帧维护,esp指向main函数栈帧的栈顶,ebp指向了main函数栈帧的栈底。
00BE1785 ret //ret指令的执行,首先是从栈顶弹出一个值,此时栈顶的值就是call指令下一条指令的地址,//此时esp+4,然后直接跳转到call指令下一条指令的地址处,继续往下执行。

回到了call指令的下一条指令的地方:
在这里插入图片描述但调用完Add函数,回到main函数的时候,继续往下执行,可以看到:

00BE185D add esp,8 //esp直接+8,相当于跳过了main函数中压栈的a'和b'
00BE1860 mov dword ptr [ebp-20h],eax //将eax中值,存档到ebp-0x20的地址处,其实就是存储到main函数中ret变量中,//而此时eax中就是Add函数中计算的x和y的和,可以看出来,本次函数的返回值是由eax寄存器带回来的。程序是在函数调用返回之后,在eax中去读取返回值的

🦖结语

到这里这篇博客已经结束啦。
到这里我们给大家完整的演示了main函数栈帧的创建,Add函数站真的额创建和销毁的过程,相信大家
已经能够基本理解函数的调用过程,函数传参的方式。
这份博客👍如果对你有帮助,给博主一个免费的点赞以示鼓励欢迎各位🔎点赞👍评论收藏⭐️,谢谢!!!
如果有什么疑问或不同的见解,欢迎评论区留言欧👀

相关文章:

函数栈帧的创建和销毁(详解)

函数栈帧的创建和销毁&#x1f996;函数栈帧是什么&#xff1f;&#x1f996;函数栈帧的创建和销毁解析&#x1f40b;栈是什么&#xff1f;&#x1f40b;认识相关寄存器和汇编指令&#x1f40b;解析函数栈帧的创建和销毁&#x1f433;预备知识&#x1f433;函数的调用堆栈&…...

【100个 Unity实用技能】 | 脚本无需挂载到游戏对象上也可执行的方法

Unity 小科普 老规矩&#xff0c;先介绍一下 Unity 的科普小知识&#xff1a; Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者&#xff0c;借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案&#xff…...

条件期望5

条件期望例题 随机图 从节点1开始, N为一个随机变量, 表示整个过程第一次出现"贪吃蛇"情形时, 所进行的步数.即Nk⇒Xk(1)∈{1,X(1),X2(1),...Xk−1(1)}其中1,X(1),X2(1),...Xk−1(1)各不相同N k \Rightarrow X^k(1) \in \{1,X(1), X^2(1),...X^{k-1}(1)\} \\ 其中1…...

RecyclerView ViewType二级

实现效果描述&#xff1a; 1、点击recyclerview中item&#xff0c;列表下方出现其他样式的item&#xff0c;作为子item&#xff0c;如下所示 所需要的java文件和xml文件有&#xff1a; 1、创建FoldAdapteradapter, 在FoldAdapter中&#xff0c;定义两种不同的类型&#xff…...

将对象或数组存在 dom元素的属性上,最后取不到完整数据,只取到 [{

目录 一、问题 二、问题及解决方法 三、总结 一、问题 1.我需要在dom元素里面添加了一个属性test存一个对象数组temp&#xff0c;以便我下一次找到这个dom元素时可以直接拿到属性里面的数据来渲染页面。 2.dom 属性上存 对象和数组&#xff0c;必须先JSON.stringify(arr),转…...

Flask源码篇:Flask路由规则与请求匹配过程(超详细,易懂)

目录1 启动时路由相关操作&#xff08;1&#xff09;分析app.route()&#xff08;2&#xff09;分析add_url_rule()&#xff08;3&#xff09;分析Rule类&#xff08;4&#xff09;分析Map类&#xff08;5&#xff09;分析MapAdapter类&#xff08;6&#xff09;分析 url_rule_…...

Jmeter接口测试教程之【参数化技巧总结】,总有一个是你不知道的

目录&#xff1a;导读 一、随机值 二、随机字符串 三、时间戳 四、唯一字符串UUID 说起接口测试&#xff0c;相信大家在工作中用的最多的还是Jmeter。 大家看这个目录就知道jmeter的应用有多广泛了&#xff1a;https://www.bilibili.com/video/BV1e44y1X78S/? JMeter是一个…...

缓存与数据库的双写一致性

背景 在高并发的业务场景下&#xff0c;系统的性能瓶颈往往是出现在数据库上&#xff0c;用户并发访问过大&#xff0c;压力都打到数据库上。所以一般都会用redis做缓存层&#xff0c;起到一个缓冲作用&#xff0c;让请求先访问到缓存层&#xff0c;而不是直接去访问数据库&am…...

力扣-213打家劫舍II(dp)

力扣-213打家劫舍II 1、题目 213. 打家劫舍 II 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房屋是紧挨着的。同时&#xff0c;相邻的房屋装有相互连通…...

关于【网格结构】岛屿类问题的通用解法DFS(深度遍历)遍历框架+回溯+剪枝总结

最近在刷力扣时遇见的问题&#xff0c;自己总结加上看了力扣大佬的知识总结写下本篇文章&#xff0c;我们所熟悉的 DFS&#xff08;深度优先搜索&#xff09;问题通常是在树或者图结构上进行的。而我们今天要讨论的 DFS 问题&#xff0c;是在一种「网格」结构中进行的。岛屿问题…...

【LeetCode】982. 按位与为零的三元组

982. 按位与为零的三元组 题目描述 给你一个整数数组 nums &#xff0c;返回其中 按位与三元组 的数目。 按位与三元组 是由下标 (i, j, k) 组成的三元组&#xff0c;并满足下述全部条件&#xff1a; 0 < i < nums.length0 < j < nums.length0 < k < num…...

Linux内核源码进程原理分析

Linux内核源码进程原理分析一、Linux 内核架构图二、进程基础知识三、Linux 进程四要素四、task_struct 数据结构主要成员五、创建新进程分析六、剖析进程状态迁移七、写时复制技术一、Linux 内核架构图 二、进程基础知识 Linux 内核把进程称为任务(task)&#xff0c;进程的虚…...

电子技术——CMOS反相器

电子技术——CMOS反相器 在本节&#xff0c;我们深入学习CMOS反相器。 电路原理 下图是我们要研究的CMOS反相器的原理图&#xff1a; 下图展示了当输入 vIVDDv_I V_{DD}vI​VDD​ 时的 iD−vDSi_D-v_{DS}iD​−vDS​ 曲线&#xff1a; 我们把 QNQ_NQN​ 当做是驱动源&#x…...

gazebo仿真轨迹规划+跟踪(不在move_base框架下)

以Tianbot为例子&#xff0c;开源代码如下&#xff1a; https://github.com/tianbot/tianbot_mini GitHub - tianbot/abc_swarm: Ant Bee Cooperative Swarm, indicating air-ground cooperation. This repository is for Tianbot Mini and RoboMaster TT swarm kit. 1.在…...

C. Good Subarrays(前缀和)

C. Good Subarrays一、问题二、分析三、代码一、问题 二、分析 这道题目的意思就是给我们一个数组&#xff0c;然后我们从数组中选取一个连续的区间&#xff0c;这个区间满足条件&#xff1a;区间内的元素和等于区间的长度。 对于区间和问题我们先想到的是前缀和的算法。 那…...

关于Facebook Messenger CRM,这里有你想要知道的一切

关于Facebook Messenger CRM&#xff0c;这里有你想要知道的一切&#xff01;想把Facebook Messenger与你的CRM整合起来吗&#xff1f;这篇博文是为你准备的! 我们将介绍有关获得Facebook Messenger CRM整合的一切信息。然后&#xff0c;我们将解释为什么你需要像SaleSmartly&a…...

ChIP-seq 分析:数据与Peak 基因注释(10)

动动发财的小手&#xff0c;点个赞吧&#xff01; 1. 数据 今天&#xff0c;我们将继续回顾我们在上一次中研究的 Myc ChIPseq。这包括用于 MEL 和 Ch12 细胞系的 Myc ChIPseq。 可在此处[1]找到 MEL 细胞系中 Myc ChIPseq 的信息和文件可在此处[2]找到 Ch12 细胞系中 Myc ChIP…...

《C++ Primer Plus》第18章:探讨 C++ 新标准(8)

使用大括号括起的初始化列表语法重写下述代码。重写后的代码不应使用数组 ar&#xff1a; class Z200 { private:int j;char ch;double z; public:Z200(int jv, char chv, zv) : j(jv), ch(chv), z(zv) {} ... };double x 8.8; std::string s "What a bracing effect!&q…...

YOLO-V5 系列算法和代码解析(八)—— 模型移植

文章目录工程目标芯片参数查阅官方文档基本流程Python 版工具链安装RKNPU2的编译以及使用方法移植自己训练的模型工程目标 将自己训练的目标检测模型【YOLO-V5s】移植到瑞芯微【3566】芯片平台&#xff0c;使用NPU推理&#xff0c;最终得到正确的结果。整个过程涉及模型量化、…...

js实现复制拷贝的兼容方法

1. 定义复制拷贝的方法 在某个工具类方法中定义该方法&#xff0c;兼容不同浏览器处理 /*** description 拷贝的类方法*/ class CopyClass {// constructor() {}setRange(input) {return new Promise((resolve, reject) > {try {// 创建range对象const range document.c…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...