Ali-Sentinel-入口控制

归档

  • GitHub: Ali-Sentinel-入口控制

测试


// 在 demo-spring-webmvc 里新建测试类public class TestMain {public static void main(String[] args) throws InterruptedException {initFlowRules(); // 初始化规则while (true) {// 1.5.0 版本开始可以直接利用 try-with-resources 特性try (Entry entry = SphU.entry("HelloWorld")) { // 进入资源 sign_demo_010// 被保护的逻辑System.out.println("hello world");// entry.exit(); // 在自动 close() 方法里会调用 exit(),不需要再手动调用} catch (BlockException ex) {// 处理被流控的逻辑System.err.println("blocked!");break;}Thread.sleep(10);}}// 初始化规则private static void initFlowRules() {List<FlowRule> rules = new ArrayList<>();FlowRule rule = new FlowRule();rule.setResource("HelloWorld");rule.setGrade(RuleConstant.FLOW_GRADE_QPS);rule.setCount(20);                  // Set limit QPS to 20.rules.add(rule);FlowRuleManager.loadRules(rules);   // 设置规则 sign_demo_020}}

查看异常栈

  • BlockExceptionFlowException 类的 fillInStackTrace() 方法注释掉才会打印完整调用栈记录

com.alibaba.csp.sentinel.slots.block.flow.FlowExceptionat com.alibaba.csp.sentinel.slots.block.flow.FlowRuleChecker.checkFlow(FlowRuleChecker.java:53) // 流控校验at com.alibaba.csp.sentinel.slots.block.flow.FlowSlot.checkFlow(FlowSlot.java:171)at com.alibaba.csp.sentinel.slots.block.flow.FlowSlot.entry(FlowSlot.java:164)at com.alibaba.csp.sentinel.slots.block.flow.FlowSlot.entry(FlowSlot.java:141)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.transformEntry(AbstractLinkedProcessorSlot.java:40)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireEntry(AbstractLinkedProcessorSlot.java:32)at com.alibaba.csp.sentinel.slots.system.SystemSlot.entry(SystemSlot.java:39)at com.alibaba.csp.sentinel.slots.system.SystemSlot.entry(SystemSlot.java:32)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.transformEntry(AbstractLinkedProcessorSlot.java:40)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireEntry(AbstractLinkedProcessorSlot.java:32)at com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot.entry(AuthoritySlot.java:42)at com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot.entry(AuthoritySlot.java:35)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.transformEntry(AbstractLinkedProcessorSlot.java:40)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireEntry(AbstractLinkedProcessorSlot.java:32)at com.alibaba.csp.sentinel.slots.statistic.StatisticSlot.entry(StatisticSlot.java:59)at com.alibaba.csp.sentinel.slots.statistic.StatisticSlot.entry(StatisticSlot.java:51)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.transformEntry(AbstractLinkedProcessorSlot.java:40)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireEntry(AbstractLinkedProcessorSlot.java:32)at com.alibaba.csp.sentinel.slots.logger.LogSlot.entry(LogSlot.java:38)at com.alibaba.csp.sentinel.slots.logger.LogSlot.entry(LogSlot.java:31)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.transformEntry(AbstractLinkedProcessorSlot.java:40)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireEntry(AbstractLinkedProcessorSlot.java:32)at com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot.entry(ClusterBuilderSlot.java:104)at com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot.entry(ClusterBuilderSlot.java:49)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.transformEntry(AbstractLinkedProcessorSlot.java:40)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireEntry(AbstractLinkedProcessorSlot.java:32)at com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot.entry(NodeSelectorSlot.java:174)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.transformEntry(AbstractLinkedProcessorSlot.java:40)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireEntry(AbstractLinkedProcessorSlot.java:32)at com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain$1.entry(DefaultProcessorSlotChain.java:31)at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.transformEntry(AbstractLinkedProcessorSlot.java:40)at com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain.entry(DefaultProcessorSlotChain.java:75)at com.alibaba.csp.sentinel.CtSph.entryWithPriority(CtSph.java:149)at com.alibaba.csp.sentinel.CtSph.entry(CtSph.java:177)at com.alibaba.csp.sentinel.CtSph.entry(CtSph.java:316)at com.alibaba.csp.sentinel.SphU.entry(SphU.java:85)at com.alibaba.csp.sentinel.demo.spring.webmvc.test.TestMain.main(TestMain.java:22) // 在 demo-spring-webmvc 里建的测试类

原理

类结构

  • com.alibaba.csp.sentinel.slotchain.ProcessorSlot

/** sign_i_001 处理器接口 */public interface ProcessorSlot<T> {/** sign_im_001 进入资源处理 */void entry(Context context, ResourceWrapper resourceWrapper, T param, int count, boolean prioritized,Object... args) throws Throwable;}
  • com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot

/** sign_c_001 处理器(单向)链节点 */public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> { // 实现接口 sign_i_001private AbstractLinkedProcessorSlot<?> next = null; // 下一个节点}

进入资源

  • 相当于获取资源,进行计数处理,被限制就会报错

  • com.alibaba.csp.sentinel.SphU

private static final Object[] OBJECTS0 = new Object[0];// sign_demo_010 进入资源public static Entry entry(String name) throws BlockException {// sph 为 CtSph 实例return Env.sph.entry(name, EntryType.OUT, 1, OBJECTS0); // sign_m_010}
  • com.alibaba.csp.sentinel.CtSph
// sign_m_010@Overridepublic Entry entry(String name, EntryType type, int count, Object... args) throws BlockException {StringResourceWrapper resource = new StringResourceWrapper(name, type);return entry(resource, count, args); // sign_m_001}// sign_m_001public Entry entry(ResourceWrapper resourceWrapper, int count, Object... args) throws BlockException {return entryWithPriority(resourceWrapper, count, false, args); // sign_m_002}// sign_m_002private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)throws BlockException {Context context = ContextUtil.getContext();... // 省略其他处理ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper); // sign_m_003... // 省略 chain 为空处理Entry e = new CtEntry(resourceWrapper, chain, context); // 创建入口(相当于锁)try {/*** 链式处理进入资源逻辑 sign_im_001* 首节点处理 sign_m_020*/chain.entry(context, resourceWrapper, null, count, prioritized, args);} ... // 省略 catch 处理return e;}// sign_m_003ProcessorSlot<Object> lookProcessChain(ResourceWrapper resourceWrapper) {ProcessorSlotChain chain = chainMap.get(resourceWrapper);if (chain == null) {synchronized (LOCK) {chain = chainMap.get(resourceWrapper);if (chain == null) {... // 省略超出限制的处理/*** 通过 SPI 获取处理链。*   配置文件: META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot*   链节点类可通过 @Spi 注解设置(顺排)顺序。* 结构参考: sign_chain_001*/chain = SlotChainProvider.newSlotChain();Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>(chainMap.size() + 1);newMap.putAll(chainMap);newMap.put(resourceWrapper, chain);chainMap = newMap; // COW 更新缓存}}}return chain;}
处理链
  • sign_chain_001

// 链结构: cur -> nextDefaultProcessorSlotChain   // 默认节点     (用于组装链)-> first                  // 头节点       (匿名实现,只传递,无逻辑) sign_f_001-> NodeSelectorSlot       // 设置统计节点 (供下游统计)-> ClusterBuilderSlot     // 设置集群节点 (供下游统计)-> LogSlot                // 日志记录     (只记录异常日志)-> StatisticSlot          // 统计         (记录 QPS、线程数等,供下游(下次)流控)-> AuthoritySlot          // 权限管理     (黑名单、白名单处理)-> SystemSlot             // 系统流制     (整个应用管控)-> FlowSlot               // 单资源流控-> DegradeSlot            // 降级处理     (相当于熔断);尾节点 end
  • 链路处理具体介绍参考:链路控制
链处理进入
  • com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain

public class DefaultProcessorSlotChain extends ProcessorSlotChain {// sign_f_001AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {@Overridepublic void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)throws Throwable {super.fireEntry(context, resourceWrapper, t, count, prioritized, args); // 只是传递给下一个节点 sign_m_022}@Overridepublic void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {super.fireExit(context, resourceWrapper, count, args);}};// sign_m_020 实现进入处理方法 sign_im_001@Overridepublic void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)throws Throwable {// 从头节点开始first.transformEntry(context, resourceWrapper, t, count, prioritized, args); // sign_m_021}}
  • com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot
// sign_m_021 传递处理进入void transformEntry(Context context, ResourceWrapper resourceWrapper, Object o, int count, boolean prioritized, Object... args)throws Throwable {T t = (T)o;entry(context, resourceWrapper, t, count, prioritized, args); // 各自节点应实现的进入处理方法 sign_im_001}// sign_m_022 发送进入@Overridepublic void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args)throws Throwable {if (next != null) {// 向下一个节点传递next.transformEntry(context, resourceWrapper, obj, count, prioritized, args); // sign_m_021}}
  • 链路处理具体介绍参考:链路控制

设置规则

  • 有点绕,用监听器做最终更改

  • com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager


public class FlowRuleManager {private static volatile Map<String, List<FlowRule>> flowRules = new HashMap<>();private static final FlowPropertyListener LISTENER = new FlowPropertyListener();private static SentinelProperty<List<FlowRule>> currentProperty = new DynamicSentinelProperty<List<FlowRule>>();static {currentProperty.addListener(LISTENER);  // 添加监听器startMetricTimerListener();             // 开启度量定时任务,默认 1s 一次}// sign_demo_020 设置规则public static void loadRules(List<FlowRule> rules) {currentProperty.updateValue(rules);     // 更新值 sign_m_201}// 内部监听器private static final class FlowPropertyListener implements PropertyListener<List<FlowRule>> {@Overridepublic synchronized void configUpdate(List<FlowRule> value) {Map<String, List<FlowRule>> rules = FlowRuleUtil.buildFlowRuleMap(value);   // 构建规则集 Map  sign_m_210if (rules != null) {flowRules = rules; // 更改规则集 Map}RecordLog.info("[FlowRuleManager] Flow rules received: {}", rules);}}}
  • com.alibaba.csp.sentinel.property.DynamicSentinelProperty

// sign_c_100 动态属性,可通过监听器扩展 (值更改的) 处理public class DynamicSentinelProperty<T> implements SentinelProperty<T> {protected Set<PropertyListener<T>> listeners = new CopyOnWriteArraySet<>();private T value = null;// sign_m_201 更新值@Overridepublic boolean updateValue(T newValue) {... // 省略:新值与旧值相同时的返回处理value = newValue; // 改值for (PropertyListener<T> listener : listeners) {listener.configUpdate(newValue); // 通知监听器}return true;}}
  • com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil
// sign_f_201private static final Function<FlowRule, String> extractResource = new Function<FlowRule, String>() {@Overridepublic String apply(FlowRule rule) {return rule.getResource(); // 使用资源名作 key}};// sign_m_210 构建规则集 Mappublic static Map<String, List<FlowRule>> buildFlowRuleMap(List<FlowRule> list) {return buildFlowRuleMap(list, null); // sign_m_211}// sign_m_211public static Map<String, List<FlowRule>> buildFlowRuleMap(List<FlowRule> list, Predicate<FlowRule> filter) {return buildFlowRuleMap(list, filter, true); // sign_m_212}// sign_m_212public static Map<String, List<FlowRule>> buildFlowRuleMap(List<FlowRule> list, Predicate<FlowRule> filter,boolean shouldSort) {/*** extractResource 参考 sign_f_201*/return buildFlowRuleMap(list, extractResource, filter, shouldSort); // sign_m_213}// sign_m_213public static <K> Map<K, List<FlowRule>> buildFlowRuleMap(List<FlowRule> list, Function<FlowRule, K> groupFunction,Predicate<FlowRule> filter, boolean shouldSort) {Map<K, List<FlowRule>> newRuleMap = new ConcurrentHashMap<>();... // 省略 list 为空处理Map<K, Set<FlowRule>> tmpMap = new ConcurrentHashMap<>();for (FlowRule rule : list) {... // 省略对 rule 进行无效校验和过滤处理... // 省略对 rule 的 limitApp 为空时填充默认值("default")的处理TrafficShapingController rater = generateRater(rule); // 创建流量控制器 sign_m_220rule.setRater(rater); // 设置规则的流量控制器K key = groupFunction.apply(rule);... // 省略 key 为空的处理Set<FlowRule> flowRules = tmpMap.get(key);if (flowRules == null) {flowRules = new HashSet<>(); // 使用 Set 防止添加重复的规则tmpMap.put(key, flowRules);}flowRules.add(rule);}Comparator<FlowRule> comparator = new FlowRuleComparator();for (Entry<K, Set<FlowRule>> entries : tmpMap.entrySet()) {List<FlowRule> rules = new ArrayList<>(entries.getValue());if (shouldSort) {Collections.sort(rules, comparator); // 对规则进行排序}newRuleMap.put(entries.getKey(), rules);}return newRuleMap;}// sign_m_220 创建流量控制器private static TrafficShapingController generateRater(FlowRule rule) {if (rule.getGrade() == RuleConstant.FLOW_GRADE_QPS) {switch (rule.getControlBehavior()) {case RuleConstant.CONTROL_BEHAVIOR_WARM_UP:return new WarmUpController(rule.getCount(), rule.getWarmUpPeriodSec(),ColdFactorProperty.coldFactor);case RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER:return new RateLimiterController(rule.getMaxQueueingTimeMs(), rule.getCount());case RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:return new WarmUpRateLimiterController(rule.getCount(), rule.getWarmUpPeriodSec(),rule.getMaxQueueingTimeMs(), ColdFactorProperty.coldFactor);case RuleConstant.CONTROL_BEHAVIOR_DEFAULT:default:// Default mode or unknown mode: default traffic shaping controller (fast-reject).}}return new DefaultController(rule.getCount(), rule.getGrade()); // 默认返回此控制器}

总结

  • 对资源的监控是通过处理器链进行处理

  • 放不放行是通过流量控制器进行判断

  • 链路处理具体介绍参考:链路控制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/3196.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Stream流入门

Stream流:操作集合和数组的工具。 Stream的三类方法&#xff1a; 获取Stream流&#xff1a;创建一条流水线&#xff0c;并把数据放上去。中间方法&#xff1a;流水线上的操作&#xff0c;可以进行多次操作。终结方法&#xff1a;一个Stream流只能有一个终结方法&#xff0c;是…

Linux交换空间的创建使用

交换空间&#xff1a; 换出&#xff1a;将内存中不常用&#xff08;冷数据&#xff09;的放去硬盘里 换出&#xff1a;内存要使用这部分数据时&#xff0c;将硬盘的这部分数据放入内存 在内存和硬盘上用来交换数据的空间就是交换空间 创建交换空间的步骤 1.去磁盘上创建一个分…

想进大厂,请先想清楚这几个问题

今天被一个小伙伴问&#xff1a;“进大厂难吗&#xff1f;” 我想都不想回答&#xff1a;“简单啊~ 从北京郎家园&#xff0c;坐817或者816&#xff0c;终点站就是大厂。” 小伙伴翻了一个大大的白眼... “我是说工作上的事&#xff01;” 瞬间懂了&#xff0c;工作场所&…

C语言 | Leetcode C语言题解之第47题全排列II

题目&#xff1a; 题解&#xff1a; int* vis;void backtrack(int* nums, int numSize, int** ans, int* ansSize, int idx, int* perm) {if (idx numSize) {int* tmp malloc(sizeof(int) * numSize);memcpy(tmp, perm, sizeof(int) * numSize);ans[(*ansSize)] tmp;return…

OssUtil工具上传文件

安装、上传、下载 1. 安装ossutil sudo -v ; curl https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash2. 配置ossutil ossutil config3. 验证是否已成功安装ossutil ossutil 如果屏幕中输出ossutil所有支持的命令&#xff0c;表明已成功安装ossutil。# 完整上传 os…

ruoyi-nbcio-plus基于vue3的flowable修正加签与跳转的前端问题

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…

idea 中导入的项目maven不自动下载依赖包

导入之后不会自动引入依赖包&#xff0c;如下图&#xff0c;external libraries 下没有依赖 解决方案&#xff1a;重新更新下maven的Local repository 即可

MMSeg搭建自己的网络

配置结构 首先&#xff0c;我们知道MMSeg矿机的配置文件很多&#xff0c;主要结构如下图所示。 在configs/_base_下是模型配置、数据集配置、以及一些其他的常规配置和运行配置&#xff0c;四类。 configs/all_config目录下存放&#xff0c;即是将四种配置聚合在一起的一个总…

产品推荐 | BittWare基于Altera Agilex“M FPGA的lA-860m加速卡

01 产品概述 BittWare的lA-860m是一款Altera Agilex“M系列FPGA卡&#xff0c;针对吞吐量和内存密集型应用进行了优化。M 系列 FPGA 具有广泛的内存层次结构&#xff0c;包括集成高带宽存储器 &#xff08;HBM2e&#xff09; 和硬内存片上网络 &#xff08;NoC&#xff09;&am…

自动化测试超详细总结

简介 软件测试是软件开发过程中一个必不可少的环节。传统的软件测试方式通常是手动测试&#xff0c;即由专业的测试人员通过手动操作软件应用程序来验证其功能和性能。然而&#xff0c;这种方式存在许多缺点&#xff0c;例如时间耗费、测试结果不稳定、测试覆盖率不够高等。 为…

百种提权及手段一览系列第3集

特权升级的危险是显而易见的。通过提升权限&#xff0c;攻击者可以绕过网络安全措施&#xff0c;从而损害数据完整性、机密性和系统可用性。对于组织而言&#xff0c;这可能会导致数据泄露、系统停机以及潜在的法律和声誉后果。识别权限升级的迹象并部署预防性网络安全措施对于…

Vue3 + Element-Plus 对接高德地图实现搜索提示选址、点击地图选址、自我定位功能(最新)

Vue3 Element-Plus 对接高德地图实现搜索提示选址、点击地图选址、自我定位功能&#xff08;最新&#xff09; 1、效果展示2、实现代码2.1 GaoDeMap.vue2.2 SystemDialog.vue2.3 UnusedList.vue.vue 1、效果展示 2、实现代码 2.1 GaoDeMap.vue <template><div style…

书生·浦语 大模型(学习笔记-5)XTuner 微调 LLM:1.8B、多模态、Agent

一&#xff1a;两种微调 增量与训练和指令微调的区别 二、数据的一生 原始数据转换为标准格式数据 添加对话模板&#xff0c;直接调用即可&#xff0c;会拼接 三、微调方案 三种加载对比 四、XTuner 五、8GB 显存玩转 LLM 五、InternLM2 1.8B模型&#xff08;相关知识&#x…

GAN 生成对抗神经网络

GAN 文章目录 GANGAN的结构GAN的目标函数GAN的训练GAN的优势和不足优势不足 GAN的结构 GAN的设计灵感来源于博弈论中的零和博弈&#xff08;Zero-sum Game&#xff09;&#xff0c;在零和博弈中&#xff0c;参与双方的收益是完全相反的&#xff0c;一方的收益必然导致另一 方的…

pymilvus执行多向量搜索

pymilvus执行多向量搜索 从 Milvus 2.4 开始&#xff0c;引入了多向量支持和混合搜索框架&#xff0c;单个collection可以支持10个向量字段。不同的向量字段可以表示不同的方面、不同的embedding模型甚至表征同一实体的不同数据模态。该功能在综合搜索场景中特别有用&#xff…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-1.3

前言&#xff1a; 本文是根据哔哩哔哩网站上视频“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”的学习笔记&#xff0c;在这里会记录下正点原子Linux ARM MX6ULL 开发板根据配套的哔哩哔哩学习视频所作的实验和笔记内容。本文大量的引用了正点原子哔哔哩网…

Python的上下文管理器(以PIL库为例)

在Python中&#xff0c;上下文管理器是一种支持上下文管理协议的对象&#xff0c;这种协议包括两个方法&#xff1a;__enter__()和__exit__()。这些方法使对象能够在代码块开始时执行一些设置或初始化工作&#xff08;通过__enter__()&#xff09;&#xff0c;以及在代码块结束…

初学python记录:力扣2739. 总行驶距离

题目&#xff1a; 卡车有两个油箱。给你两个整数&#xff0c;mainTank 表示主油箱中的燃料&#xff08;以升为单位&#xff09;&#xff0c;additionalTank 表示副油箱中的燃料&#xff08;以升为单位&#xff09;。 该卡车每耗费 1 升燃料都可以行驶 10 km。每当主油箱使用了…

new String和直接赋值的一些问题

分析1 我们先看以下代码&#xff1a; String str1 "abc"; // 在常量池中String str2 new String("abc"); // 在堆上System.out.println(str1 str2)以上结果的输出是什么&#xff1f; 输出&#xff1a;false 前置知识&#xff1a; 在JVM中&#xff0c…

C++静态变量

C语言中与“静态”相关的词包括&#xff0c;静态全局变量&#xff0c;静态局部变量和静态函数&#xff0c;关键词是static。C语言中的变量从作用域分&#xff0c;可以分为全局变量和局部变量&#xff1b;从存储方式分&#xff0c;可以分为静态存储方式和动态存储方式。 1. 静态…