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

linux-kernel-ecmp-ipv4

当使用ip route add/del添加或者删除路由时,通过触发netlink发送信息到各协议路由系统注册的netlink处理函数,如add时调用函数为inet_rtm_newroute。Equal Cost Multi Path,在ip交换网络中存在到达同一目的地址的多条不同的路径,而且每条路径消耗的资源(cost)一样时。内核定制了CONFIG_IP_ROUTE_MULTIPATH时,ip层在收到等价的ip报文时,会根据配置的策略通过不通的路径均衡转发出去,使得转发达到负载均衡的目的。

1、路由初始化大概结构

路由初始化主要函数为:

//路由缓存初始化
int __init ip_rt_init(void)
{int rc = 0;#ifdef CONFIG_IP_ROUTE_CLASSID//基于路由的分类器,每个CPU256个变量ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct), __alignof__(struct ip_rt_acct));if (!ip_rt_acct)panic("IP: failed to allocate ip_rt_acct\n");
#endif//路由缓存池ipv4_dst_ops.kmem_cachep =kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep;//初始化每CPU变量if (dst_entries_init(&ipv4_dst_ops) < 0)panic("IP: failed to allocate ipv4_dst_ops counter\n");//初始化每CPU变量if (dst_entries_init(&ipv4_dst_blackhole_ops) < 0)panic("IP: failed to allocate ipv4_dst_blackhole_ops counter\n");//建立路由缓存hash表rt_hash_table = (struct rt_hash_bucket *)alloc_large_system_hash("IP route cache",sizeof(struct rt_hash_bucket),rhash_entries,(totalram_pages >= 128 * 1024) ?15 : 17,0,&rt_hash_log,&rt_hash_mask,rhash_entries ? 0 : 512 * 1024);//初始化路由缓存hash表memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));//每个hash表rt_hash_lock_init();//设置gc时间和缓存最大数量ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1);ip_rt_max_size = (rt_hash_mask + 1) * 16;//初始化devinet_init();//注册通知链和创建alias缓存ip_fib_init();//注册gc任务INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func);expires_ljiffies = jiffies;schedule_delayed_work(&expires_work,net_random() % ip_rt_gc_interval + ip_rt_gc_interval);if (ip_rt_proc_init())pr_err("Unable to create route proc files\n");
#ifdef CONFIG_XFRMxfrm_init();xfrm4_init(ip_rt_max_size);
#endif//注册netlink消息rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL, NULL);#ifdef CONFIG_SYSCTLregister_pernet_subsys(&sysctl_route_ops);
#endifregister_pernet_subsys(&rt_genid_ops);return rc;
}

当使用ip route add/del添加或者删除路由时,通过触发netlink发送信息到各协议路由系统注册的netlink处理函数,如add时调用函数为inet_rtm_newroute。 

void __init ip_fib_init(void)
{//注册netlink路由添加、删除和dump命令处理函数rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);//初始化路由表和路由缓存register_pernet_subsys(&fib_net_ops);//注册通知链处理函数,监听系统其它模块信息register_netdevice_notifier(&fib_netdev_notifier);register_inetaddr_notifier(&fib_inetaddr_notifier);//初始化路由用到的缓存池fib_trie_init();
}

而当协议报文下发时,调用ip_rt_init注册的inet_rtm_getroute进行路由转发。

sys_socketcall()-->sys_connect()-->inet_stream_connect()-->tcp_v4_connect()-->ip_route_connect()-->inet_rtm_getroute()。

2、inet_rtm_getroute

inet_rtm_getroute分配sk的路由信息,通过fib_lookup查询该dip的路由信息,最终由函数ip_mkroute_input创建路由缓存项。

int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
{
...skb = inet_rtm_getroute_build_skb(src, dst, ip_proto, sport, dport);if (!skb)return -ENOBUFS;memset(&fl4, 0, sizeof(fl4));fl4.daddr = dst;fl4.saddr = src;fl4.flowi4_tos = rtm->rtm_tos;fl4.flowi4_oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0;fl4.flowi4_mark = mark;fl4.flowi4_uid = uid;if (sport)fl4.fl4_sport = sport;if (dport)fl4.fl4_dport = dport;fl4.flowi4_proto = ip_proto;rcu_read_lock();if (iif) {struct net_device *dev;dev = dev_get_by_index_rcu(net, iif);if (!dev) {err = -ENODEV;goto errout_rcu;}fl4.flowi4_iif = iif; /* for rt_fill_info */skb->dev	= dev;skb->mark	= mark;//路由此skb,获取路由信息err = ip_route_input_rcu(skb, dst, src, rtm->rtm_tos,dev, &res);rt = skb_rtable(skb);if (err == 0 && rt->dst.error)err = -rt->dst.error;} else {fl4.flowi4_iif = LOOPBACK_IFINDEX;rt = ip_route_output_key_hash_rcu(net, &fl4, &res, skb);err = 0;if (IS_ERR(rt))err = PTR_ERR(rt);elseskb_dst_set(skb, &rt->dst);}
...
}
int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,u8 tos, struct net_device *dev, struct fib_result *res)
{...return ip_route_input_slow(skb, daddr, saddr, tos, dev, res);
}static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,u8 tos, struct net_device *dev, struct fib_result *res)
{
...err = fib_lookup(net, &fl4, res, 0);if (err != 0) {if (!IN_DEV_FORWARD(in_dev))err = -EHOSTUNREACH;goto no_route;}make_route:err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys);
...
}

3、 ip_mkroute_input--ecmp选择出口路由

如果在上述fib_lookup流程中查找到该dip包含多个路径,则由函数fib_multipath_hash计算hash值,之后,函数fib_select_multipath通过hash值选择其中的某个下一跳。

static int ip_mkroute_input(struct sk_buff *skb,struct fib_result *res,struct in_device *in_dev,__be32 daddr, __be32 saddr, u32 tos,struct flow_keys *hkeys)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATHif (res->fi && res->fi->fib_nhs > 1) {int h = fib_multipath_hash(res->fi->fib_net, NULL, skb, hkeys);fib_select_multipath(res, h);}
#endif/* create a routing cache entry */return __mkroute_input(skb, res, in_dev, daddr, saddr, tos);
}

 路径数量判断:

如果fib_info的成员nh(下一跳对象)有值,根据其获得路径的数量。其次,nh为空时,使用fib_info结构成员fib_nhs的数量值。如果下一跳对象为组,并且组内有多个路径,返回组内路径数量。否则,返回1。

static inline unsigned int fib_info_num_path(const struct fib_info *fi)
{if (unlikely(fi->nh))return nexthop_num_path(fi->nh);return fi->fib_nhs;
}
static inline unsigned int nexthop_num_path(const struct nexthop *nh)
{unsigned int rc = 1;if (nh->is_group) {struct nh_group *nh_grp;nh_grp = rcu_dereference_rtnl(nh->nh_grp);if (nh_grp->mpath)rc = nh_grp->num_nh;}return rc;
}

3.1 fib_multipath_hash--多路径hash值的计算:

proc文件中fib_multipath_hash_policy参数用于指定路径选择时使用的hash策略。

# cat /proc/sys/net/ipv4/fib_multipath_hash_policy

0:基于三层头部数据做hash

1:基于四层hash

int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,const struct sk_buff *skb, struct flow_keys *flkeys)
{struct flow_keys hash_keys;u32 mhash;switch (net->ipv4.sysctl_fib_multipath_hash_policy) {case 0 :break;case 1:break;mhash = flow_hash_from_keys(&hash_keys);return mhash >> 1;
}

如果哈希策略fib_multipath_hash_policy值为0,使用流结构fl4中保存的源和目的IP地址,但是,如果skb有值,将使用函数ip_multipath_l3_keys获取源和目的IP地址,对于ICMP报文,此函数将得到内部IP头部中的IP地址信息;即,hash = sip xor dip。

case 0:memset(&hash_keys, 0, sizeof(hash_keys));hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;if (skb) {ip_multipath_l3_keys(skb, &hash_keys);} else {hash_keys.addrs.v4addrs.src = fl4->saddr;hash_keys.addrs.v4addrs.dst = fl4->daddr;}break;static void ip_multipath_l3_keys(const struct sk_buff *skb,struct flow_keys *hash_keys)
{const struct iphdr *outer_iph = ip_hdr(skb);const struct iphdr *key_iph = outer_iph;const struct iphdr *inner_iph;const struct icmphdr *icmph;struct iphdr _inner_iph;struct icmphdr _icmph;if (likely(outer_iph->protocol != IPPROTO_ICMP))goto out;if (unlikely((outer_iph->frag_off & htons(IP_OFFSET)) != 0))goto out;icmph = skb_header_pointer(skb, outer_iph->ihl * 4, sizeof(_icmph),&_icmph);if (!icmph)goto out;if (icmph->type != ICMP_DEST_UNREACH &&icmph->type != ICMP_REDIRECT &&icmph->type != ICMP_TIME_EXCEEDED &&icmph->type != ICMP_PARAMETERPROB)goto out;inner_iph = skb_header_pointer(skb,outer_iph->ihl * 4 + sizeof(_icmph),sizeof(_inner_iph), &_inner_iph);if (!inner_iph)goto out;key_iph = inner_iph;
out:hash_keys->addrs.v4addrs.src = key_iph->saddr;hash_keys->addrs.v4addrs.dst = key_iph->daddr;
}

当哈希策略值为1,根据skb是否为空,由以下两种处理。如果skb有值,并且已经计算了四层的哈希值,这里直接使用此值。否则,根据流的key值得到四层数据,包括:源和目的地址,源和目的端口号以及协议号。另外,如果skb为空,由flowl4结构的参数fl4中获取四层信息。

	case 1:/* skb is currently provided only when forwarding */if (skb) {unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;struct flow_keys keys;/* short-circuit if we already have L4 hash present */if (skb->l4_hash)return skb_get_hash_raw(skb) >> 1;memset(&hash_keys, 0, sizeof(hash_keys));if (!flkeys) {skb_flow_dissect_flow_keys(skb, &keys, flag);flkeys = &keys;}hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;hash_keys.addrs.v4addrs.src = flkeys->addrs.v4addrs.src;hash_keys.addrs.v4addrs.dst = flkeys->addrs.v4addrs.dst;hash_keys.ports.src = flkeys->ports.src;hash_keys.ports.dst = flkeys->ports.dst;hash_keys.basic.ip_proto = flkeys->basic.ip_proto;} else {memset(&hash_keys, 0, sizeof(hash_keys));hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;hash_keys.addrs.v4addrs.src = fl4->saddr;hash_keys.addrs.v4addrs.dst = fl4->daddr;hash_keys.ports.src = fl4->fl4_sport;hash_keys.ports.dst = fl4->fl4_dport;hash_keys.basic.ip_proto = fl4->flowi4_proto;}break;}

3.2 fib_select_multipath-->路由出口选择

proc系统下的fib_multipath_use_neigh的值用于表示是否根据邻居表的状态选择路径,默认为0,表示不使用邻居表状态信息。

# cat /proc/sys/net/ipv4/fib_multipath_use_neigh

遍历所有的下一跳,如果没有开启fib_multipath_use_neigh,判断hash值是否小于当前下一跳的fib_nh_upper_bound值,为真则在结果中记录下当前下一跳的索引值和相关信息。在开启fib_multipath_use_neigh的情况下,将通过函数fib_good_nh来判断是否为可用的下一跳,fib_nh_upper_bound的值不仅与自身下一跳地址的权重相关,而且与当前路由的其它下一跳地址的权重也相关(fib_rebalance)。在下一跳地址数组中,fib_nh_upper_bound的值有小到大,被设置RTNH_F_DEAD标记的下一跳的fib_nh_upper_bound值为-1,不会被选择。

void fib_select_multipath(struct fib_result *res, int hash)
{struct fib_info *fi = res->fi;struct net *net = fi->fib_net;bool first = false;for_nexthops(fi) {if (net->ipv4.sysctl_fib_multipath_use_neigh) {if (!fib_good_nh(nh))continue;if (!first) {res->nh_sel = nhsel;first = true;}}if (hash > atomic_read(&nh->nh_upper_bound))continue;res->nh_sel = nhsel;return;} endfor_nexthops(fi);
}

相关文章:

linux-kernel-ecmp-ipv4

当使用ip route add/del添加或者删除路由时&#xff0c;通过触发netlink发送信息到各协议路由系统注册的netlink处理函数&#xff0c;如add时调用函数为inet_rtm_newroute。Equal Cost Multi Path,在ip交换网络中存在到达同一目的地址的多条不同的路径&#xff0c;而且每条路径…...

蒙特卡洛树搜索(MTCS)

一、目标 一种启发式的搜索算法&#xff0c;在搜索空间巨大的场景下比较有效 算法完成后得到一棵树&#xff0c;这棵树可以实现&#xff1a;给定一个游戏状态&#xff0c;直接选择最佳的下一步 二、算法四阶段 1、选择&#xff08;Selection&#xff09; 父节点选择UCB值最…...

【Verilog】——Verilog简介

目录 1.简介 2.什么是HDL以及HDL的功能 3.Verilog和C语言的比较 4.Verilog的用途 5.数字系统的抽象层次 1.系统级 2.算法级 3.RTL级&#xff08;寄存器变换级&#xff09; 6.数字系统抽象层级 7.自顶向下的结构化设计方法 8.Verilog建模 9.Verilog概述 10.Verilog模块的基本…...

【Python从入门到进阶】10、流程控制语句-循环语句(for-while)

接上篇《9、流程控制语句-条件语句(if-else)》 上一篇我们学习了Python的控制流语句的概念&#xff0c;以及其中的条件语句(if/else)&#xff0c;本篇我们来学习控制流语句中的循环语句(for/while)。 一、Python中的循环 Python的循环结构就是让程序“杀个回马枪”&#xff0…...

超全的命令(代码)执行漏洞无回显的姿势总结(附带详细代码和测试分析过程)

目录 漏洞代码 突破方式 重定向 dnslog外部通信 burpsuite burpcollaborator外部通信 日志监听 netcat监听 反弹shell的各种姿势 漏洞代码 <?php shell_exec($_GET[a]); ?>这里使用了无回显的shell执行函数shell_exec&#xff0c;给html目录的权限是777 突破方…...

STM32MP157-Linux音频应用编程-简易语音助手

文章目录前言STM32MP157简易语音助手alsa-lib简介&#xff1a;移植alsa-lib库&#xff1a;libcurl库简介&#xff1a;移植libcurl库&#xff1a;API调用修改asrmain.c文件修改token.c文件录音文件IO打开音频文件硬件控制sysfs文件系统数据解析和控制多线程主循环实现效果及注意…...

Python-OpenCV图像处理:学习图像算术运算,如加减法、图像混合、按位运算,以及如何实现它们

目录 目标 图像添加 图像混合算法 按位运算 目标 学习对图像的几种算术运算,如加法、减法、位运算等。了解这些功能:cv.add()、...

并发编程——ReentrantLock

如果有兴趣了解更多相关内容&#xff0c;欢迎来我的个人网站看看&#xff1a;耶瞳空间 一&#xff1a;基本介绍 从Java 5开始&#xff0c;引入了一个高级的处理并发的java.util.concurrent包&#xff0c;它提供了大量更高级的并发功能&#xff0c;能大大简化多线程程序的编写…...

English Learning - L2 第 3 次小组纠音 [ʌ] [ɒ] [ʊ] [ɪ] [ə] [e] 2023.3.4 周六

English Learning - L2 第 3 次小组纠音 [ʌ] [ɒ] [ʊ] [ɪ] [ə] [e] 2023.3.4 周六共性问题小元音 [ʌ]小元音 [ɒ]小元音 [ʊ]小元音 [ɪ]小元音 [ə]小元音 [e]我的发音问题纠音过程共性问题 小元音 [ʌ] 口型容易偏大 解决办法&#xff1a;因为嘴角没有放松&#xff0c…...

STM32之关门狗

看门狗介绍在由单片机构成的微型计算机系统中&#xff0c;由于单片机的工作常常会受到来自外界电磁场的干扰&#xff0c;造成程序的跑飞&#xff0c;而陷入死循环&#xff0c;程序的正常运行被打断&#xff0c;由单片机控制的系统无法继续工作&#xff0c;会造成整个系统的陷入…...

Apollo控制部分1-- ControlComponent组件介绍

Apollo控制部分1-- ControlComponent组件介绍摘要一、ControlComponent1、启动文件解析2、ControlComponent()组件函数解析1&#xff09;ControlComponent::ControlComponent() 构造函数2&#xff09;ControlComponent::Init() 初始化函数&#xff08;执行一次&#xff09;3&am…...

0626-0631韩顺平Java Buffered字节处理流 学习笔记

如何去构建字节流package com.hspedu.outputstream_;import java.io.*;/*** author abner* version 1.0*/ public class BufferedCopy02 {public static void main(String[] args) {String srcFilePath "D:\\Users\\Pictures\\Camera Roll\\Pierre-Auguste_Renoir,_Le_Mo…...

【网络】序列化和反序列化

&#x1f941;作者&#xff1a; 华丞臧. &#x1f4d5;​​​​专栏&#xff1a;【网络】 各位读者老爷如果觉得博主写的不错&#xff0c;请诸位多多支持(点赞收藏关注)。如果有错误的地方&#xff0c;欢迎在评论区指出。 推荐一款刷题网站 &#x1f449; LeetCode刷题网站 文章…...

【代码随想录训练营】【Day32】第八章|贪心算法|122.买卖股票的最佳时机II |55. 跳跃游戏|45.跳跃游戏II

买卖股票的最佳时机II 题目详细&#xff1a;LeetCode.122 买卖股票的最佳时机&#xff0c;怎么都能够想出来个思路&#xff0c;假如我们每天都能预知明天的股票是涨是降&#xff0c;那么贪心策略就是在涨之前买股票&#xff0c;在降的前一天卖掉&#xff0c;这就是买卖股票的…...

constexpr 和 常量表达式

&#x1f440;&#x1f440;常量表达式 常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。 字面值属于常量表达式&#xff0c;用常量表达式初始化的const对象也是常量表达式。 那么是什么来就决定是不是常量表达式呢&#xff1f;一个对象是不是常量表达式主要…...

Vue响应式原理————Object.defineProperty()和proxy的用法分享

Vue框架一个比较核心的功能就是我们的数据是响应式的&#xff0c;这样我们在修改数据的时候&#xff0c;页面会自动帮我们更新&#xff0c;那么想要实现这个功能就要实现对一个数据的劫持&#xff0c;即在取值和设置值的同时我们能够检测到即数据劫持。vue2响应式的实现原理所依…...

CSDN 编程竞赛三十四期题解

竞赛总览 CSDN 编程竞赛三十四期&#xff1a;比赛详情 (csdn.net) 本期的题目和第三十一期竞赛的题目竟然高度重合&#xff0c;真不知道该写点什么了。 不过&#xff0c;上次那道测试数据有bug的题已经修复了&#xff0c;答题过程挺顺利的&#xff0c;没有遇到新的问题。 竞…...

C#教程06 运算符

文章目录 一、算术运算符加法运算符(+)减法运算符(-)乘法运算符(*)除法运算符(/)二、逻辑运算符与运算符(&&)或运算符(||)非运算符(!)三、比较运算符等于运算符(==)大于运算符(>)小于运算符(<)大于等于运算符(>=)小于等于运算符(<=…...

软测入门(六)pytest单元测试

pytest pytest是python的一种单元测试框架&#xff0c;同自带的unit test测试框架类似&#xff0c;但pytest更简洁高效。 单元测试&#xff1a; 测试 函数、类、方法能不能正常运行测试的结果是否符合我们的预期结果 安装 pip install -U pytest基本使用 通过pytest包使用…...

经典分类模型回顾5—DenseNet实现图像分类(matlab)

DenseNet&#xff0c;全称为Densely Connected Convolutional Networks&#xff0c;中文名为密集连接卷积网络&#xff0c;是由李沐等人在2017年提出的一种深度神经网络架构。 DenseNet旨在解决深度神经网络中的梯度消失问题和参数数量过多的问题&#xff0c;通过构建密集连接…...

基于flask+bootstrap+echarts+mysql的鱼村小馆订餐后台管理系统

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…...

Spark使用Log4j将日志发送到Kafka

文章目录自定义KafkaAppender修改log4j.properties配置启动命令配置添加参数启动之后可以在Kafka中查询发送数据时区问题-自定义实现JSONLayout解决自定义JSONLayout.java一键应用可能遇到的异常ClassNotFoundException: xxx.KafkaLog4jAppenderUnexpected problem occured dur…...

c++类与对象整理(上)

目录 1.类的引入 2.类的定义 3.类的访问限定符及封装 1&#xff09;访问限定符 2&#xff09;封装 4.类的作用域 5.类的实例化 6.类的对象大小的计算 1&#xff09;类对象的存储方式 2&#xff09;内存对齐和大小计算 ​编辑 7.类成员函数的this指针 1&#xff09…...

Docker学习(十九)什么是镜像的元数据?

在 Docker 中&#xff0c;镜像的元数据是指与镜像相关的所有信息&#xff0c;包括镜像的名称和标签、作者、描述、创建日期、环境变量、命令等。这些信息都是通过 Dockerfile 或命令行创建和指定的。 镜像的元数据被存储在 Docker Registry 中&#xff0c;并在使用 docker pull…...

Python如何获取弹幕?给你介绍两种方式

前言 弹幕可以给观众一种“实时互动”的错觉&#xff0c;虽然不同弹幕的发送时间有所区别&#xff0c;但是其只会在视频中特定的一个时间点出现&#xff0c;因此在相同时刻发送的弹幕基本上也具有相同的主题&#xff0c;在参与评论时就会有与其他观众同时评论的错觉。 在国内…...

JAVA- AOP 面向切面编程 Aspect切面工具类 记录特定方法执行时的入参、执行时间、返参等内容

背景&#xff1a;JAVA项目&#xff0c;使用AOP对指定函数进行切面。能够记录特定方法执行时的入参、执行时间、返参结果等内容。 文章目录1、自定义注解类1.1 Target1.2 Retention2、Aspect切面工具2.1 JointPoint2.2 Pointcut2.3 切面中的相关注解3、同一个类里调用AOP4、其他…...

「史上最全的 TCG 规范解读」TCG 规范架构概述(下)

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强不同计算机平台上计算环境的安全性。TCG 于 2003 年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Allia…...

GDScript 导出变量 (4.0)

概述 导出变量的功能在3.x版本中也是有的&#xff0c;但是4.0版本对其进行了语法上的改进。 导出变量在日常的游戏制作中提供节点的自定义参数化调节功能时非常有用&#xff0c;除此之外还用于自定义资源。 本文是&#xff08;Bilibili巽星石&#xff09;在4.0官方文档《GDScr…...

JAVA知识点全面总结6:泛型反射和注解

六.JAVA知识点全面总结6泛型反射和注解 1.什么是泛型?可以用在哪里&#xff1f; 2.泛型擦除机制是什么&#xff1f;为什么擦除&#xff1f; 3.通配符是什么&#xff1f;作用是什么&#xff1f; 未更新 1.注解是什么&#xff1f;有什么用&#xff1f; 2.注解的自定义和实…...

死代码删除(DCE,Dead Code Elimination)和激进的死代码删除(ADCE,Aggressive DCE)

死代码删除&#xff08;DCE&#xff0c;Dead Code Elimination&#xff09;和激进的死代码删除&#xff08;ADCE&#xff0c;Aggressive DCE&#xff09;死代码删除&#xff08;DCE&#xff0c;Dead Code Elimination&#xff09;DCE简介DCE基本算法激进的死代码删除&#xff0…...