<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Learning on chengzhycn&#39;s blog</title>
		<link>https://blog.jinzhi.site/categories/learning/</link>
		<description>Recent content in Learning on chengzhycn&#39;s blog</description>
		<generator>Hugo</generator>
		<language>en-us</language>
		
		
		
		
			<lastBuildDate>Tue, 28 Apr 2026 15:18:28 +0800</lastBuildDate>
		
			<atom:link href="https://blog.jinzhi.site/categories/learning/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>Envoy Go HTTP Filter</title>
				<link>https://blog.jinzhi.site/posts/2026-04/envoy-go-http-filter/</link>
				<pubDate>Tue, 28 Apr 2026 15:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2026-04/envoy-go-http-filter/</guid>
				<description>&lt;p&gt;Go HTTP 过滤器 (&lt;code&gt;envoy.filters.http.golang&lt;/code&gt;) 允许使用 Go 编写 Envoy HTTP 过滤器。Go 代码被编译为共享库 (&lt;code&gt;.so&lt;/code&gt;)，在运行时通过 &lt;code&gt;dlopen&lt;/code&gt; 加载，并借由 CGo bridge 集成到 Envoy 的 C++ 过滤器链中。&lt;/p&gt;&#xA;&lt;h2 id=&#34;架构&#34;&gt;架构&lt;/h2&gt;&#xA;&lt;p&gt;Go HTTP Filter 主要分为两端：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;C++ 端&lt;/strong&gt;：负责 DSO 加载、过滤器链集成以及线程安全。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Go 端&lt;/strong&gt;：通过 Go SDK 实现过滤器逻辑，通过 CGo 与 C++ 通信。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;ABI 边界由 &lt;code&gt;contrib/golang/common/go/api/api.h&lt;/code&gt; 中的共享 C 结构体定义。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/envoy-go-http-filter/1d4a997271052a5a6344e5235da18b13_MD5.jpeg&#34; alt=&#34;1d4a997271052a5a6344e5235da18b13_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;dso-动态共享对象-加载机制&#34;&gt;DSO (动态共享对象) 加载机制&lt;/h2&gt;&#xA;&lt;p&gt;Go HTTP 过滤器通过 &lt;code&gt;contrib/golang/common/dso/&lt;/code&gt; 中定义的专用 DSO 机制加载 Go 编译的共享库。这与 Envoy 核心扩展中的 &lt;code&gt;dynamic_modules&lt;/code&gt; 是两套独立的实现。&lt;/p&gt;&#xA;&lt;h3 id=&#34;核心组件&#34;&gt;核心组件&lt;/h3&gt;&#xA;&lt;h4 id=&#34;1-dso-管理器-dsomanager&#34;&gt;1. DSO 管理器 (DsoManager)&lt;/h4&gt;&#xA;&lt;p&gt;&lt;code&gt;DsoManager&lt;/code&gt; 类 (&lt;code&gt;contrib/golang/common/dso/dso.h&lt;/code&gt;) 负责管理共享库的生命周期：&lt;/p&gt;</description>
			</item>
			<item>
				<title>nano-vllm 代码流程</title>
				<link>https://blog.jinzhi.site/posts/2026-01/nano-vllm-%E4%BB%A3%E7%A0%81%E6%B5%81%E7%A8%8B/</link>
				<pubDate>Tue, 27 Jan 2026 09:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2026-01/nano-vllm-%E4%BB%A3%E7%A0%81%E6%B5%81%E7%A8%8B/</guid>
				<description>&lt;h2 id=&#34;整体架构图&#34;&gt;整体架构图&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────┐&#xA;│                         用户入口层                               │&#xA;│  example.py → LLM.generate() → add_request() + step() 循环      │&#xA;└─────────────────────────────────────────────────────────────────┘&#xA;                                │&#xA;                                ▼&#xA;┌─────────────────────────────────────────────────────────────────┐&#xA;│                         引擎层 (Engine)                          │&#xA;│  ┌─────────────┐   ┌─────────────┐   ┌──────────────────┐      │&#xA;│  │  Scheduler  │ → │ ModelRunner │ → │  BlockManager    │      │&#xA;│  │  (调度器)    │   │ (模型执行器) │   │  (KV Cache管理)  │      │&#xA;│  └─────────────┘   └─────────────┘   └──────────────────┘      │&#xA;└─────────────────────────────────────────────────────────────────┘&#xA;                                │&#xA;                                ▼&#xA;┌─────────────────────────────────────────────────────────────────┐&#xA;│                         模型层 (Models)                          │&#xA;│  Qwen3ForCausalLM → Qwen3Model → [Qwen3DecoderLayer x N]       │&#xA;└─────────────────────────────────────────────────────────────────┘&#xA;                                │&#xA;                                ▼&#xA;┌─────────────────────────────────────────────────────────────────┐&#xA;│                         算子层 (Layers)                          │&#xA;│  Attention │ Linear │ LayerNorm │ RoPE │ Activation │ Sampler  │&#xA;└─────────────────────────────────────────────────────────────────┘&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;推理服务流程详解&#34;&gt;推理服务流程详解&lt;/h2&gt;&#xA;&lt;h3 id=&#34;阶段-1-初始化阶段&#34;&gt;阶段 1: 初始化阶段&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# example.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;llm&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LLM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;enforce_eager&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tensor_parallel_size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;调用链：&lt;/strong&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>KubeCon North America 2025 Review</title>
				<link>https://blog.jinzhi.site/posts/2025-11/kubecon-north-america-2025-review/</link>
				<pubDate>Sun, 23 Nov 2025 15:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-11/kubecon-north-america-2025-review/</guid>
				<description>&lt;p&gt;KubeCon North America 2025 13号结束了，官网上也有了些会议资料。挑了几个感兴趣的话题总结下。&lt;/p&gt;&#xA;&lt;h2 id=&#34;dynamic-routing-with-multi-cluster-inference-gateway&#34;&gt;Dynamic Routing with Multi-Cluster Inference Gateway&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://kccncna2025.sched.com/event/27FeP/ai-inference-without-boundaries-dynamic-routing-with-multi-cluster-inference-gateway-rob-scott-google-daneyon-hansen-soloio?iframe=no&amp;amp;w=100%25&amp;amp;sidebar=yes&amp;amp;bg=no&#34;&gt;https://kccncna2025.sched.com/event/27FeP/ai-inference-without-boundaries-dynamic-routing-with-multi-cluster-inference-gateway-rob-scott-google-daneyon-hansen-soloio?iframe=no&amp;w=100%&amp;sidebar=yes&amp;bg=no&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;这段时间正好在做 AI 网关，这个话题可以说是“瞌睡了送枕头”。&lt;/p&gt;&#xA;&lt;p&gt;推理服务和传统 API 流量相比，在 payload，响应时间，后端资源开销上都有着很大的差异（见下图）。&#xA;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/kubecon-north-america-2025-review/2781cd595fe30c8da311d124a8e4ee35_MD5.jpeg&#34; alt=&#34;2781cd595fe30c8da311d124a8e4ee35_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;因此，推理网关需要做到后端负载感知的调度（传统 API 网关也有类似的方案，尤其是在后端机型不一样，普通的 rr 无法均匀负载时，做后端负载感知动态调权）。在 Gateway 和推理实例间引入了一个 EPP（Endpoint Picker）组件（注：EPP 现在也是 Kubernetes 做推理服务的一个通用组件），采集推理实例的指标来动态选择推理后端。&#xA;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/kubecon-north-america-2025-review/3462773fb295a9dabdabc886b1de43ca_MD5.jpeg&#34; alt=&#34;3462773fb295a9dabdabc886b1de43ca_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;benchmark 数据显示，使用推理网关相比传统负载均衡，推理实例间的负载更加均衡，请求排队更少，从而降低了响应时间。&lt;/p&gt;&#xA;&lt;p&gt;在多集群场景下，这套方案需要解决 3 个问题：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;服务发现：Cluster Inference Services 如何暴露给 Gateway？&lt;/li&gt;&#xA;&lt;li&gt;后端选择：Gateway 如何在多集群间分配流量？&lt;/li&gt;&#xA;&lt;li&gt;路由模式：流量如何从 Gateway 转发到集群？&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;第一个问题作者提了 3 个解决方法：&#xA;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/kubecon-north-america-2025-review/fd7a6ffacbfd58fcd6482dd40b861461_MD5.jpeg&#34; alt=&#34;fd7a6ffacbfd58fcd6482dd40b861461_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;不是关注重点，略过。&lt;/p&gt;&#xA;&lt;p&gt;第二个问题，简单的 RR 和 Active-Passive 肯定就失去了推理网关负载感知的优势。所以，在 EPP 感知负载之外，Gateway 也得做负载感知。作者也提了两个方法：&#xA;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/kubecon-north-america-2025-review/1d3df4bac299f39b0c917b886bab2a27_MD5.jpeg&#34; alt=&#34;1d3df4bac299f39b0c917b886bab2a27_MD5&#34;&gt;&#xA;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/kubecon-north-america-2025-review/f4bd518bc6dce2999d5805d5b2d46dac_MD5.jpeg&#34; alt=&#34;f4bd518bc6dce2999d5805d5b2d46dac_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;从层级上来说，EPP Aggregate Metrics 方案更加简洁，毕竟在 EPP 上还得做二次调度。&lt;/p&gt;&#xA;&lt;p&gt;最后一个问题，如果 EPP 能跨集群直接访问，direct routing 是最合适的方式，不行的话再加一层网关，使用 Cluster-Local Gateway 做暴露也能访问。&lt;/p&gt;</description>
			</item>
			<item>
				<title>网关的限流方案</title>
				<link>https://blog.jinzhi.site/posts/2025-11/%E7%BD%91%E5%85%B3%E7%9A%84%E9%99%90%E6%B5%81%E6%96%B9%E6%A1%88/</link>
				<pubDate>Sun, 16 Nov 2025 15:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-11/%E7%BD%91%E5%85%B3%E7%9A%84%E9%99%90%E6%B5%81%E6%96%B9%E6%A1%88/</guid>
				<description>&lt;p&gt;&lt;strong&gt;Note：本文由 Google Gemini DeepResearch 生成。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;1网关限流服务的战略必要性与流量控制架构&#34;&gt;1.网关限流服务的战略必要性与流量控制架构&lt;/h2&gt;&#xA;&lt;h3 id=&#34;11-网关在流量管理中的控制点角色与核心必要性&#34;&gt;1.1. 网关在流量管理中的控制点角色与核心必要性&lt;/h3&gt;&#xA;&lt;p&gt;API 网关在现代微服务架构中扮演着至关重要的流量控制点角色，负责管理北向（Ingress）和南向（Egress）的流量。对流量实施限制（即限流）是保障上游服务稳定性、维持系统可用性和实现资源公平分配的核心防御机制。&lt;/p&gt;&#xA;&lt;p&gt;限流服务的战略必要性主要体现在以下几个方面：&lt;/p&gt;&#xA;&lt;p&gt;首先，限流是防止系统过载和雪崩效应的关键。当面临突发流量高峰时，如不加限制，后台服务器可能因资源耗尽而被压垮。通过限制客户端在指定时间窗内的请求次数，网关可以有效地保护应用编程接口（API）及其背后的微服务。其次，限流是抵御恶意攻击的有效手段，尤其是分布式拒绝服务攻击（DDoS）或防止未受限制的网络爬虫过度消耗计算资源。如果任由客户端无限制地访问上游服务，系统的可用性将受到负面影响。&lt;/p&gt;&#xA;&lt;p&gt;从架构设计的角度看，网关作为请求进入系统的唯一入口，是实施全局限流策略的最佳位置，可以根据 IP、API 密钥、特定消费者（Consumer）或其他定制标准来应用限流规则。&lt;/p&gt;&#xA;&lt;h3 id=&#34;12-限流策略的粒度层次结构与定制化响应&#34;&gt;1.2. 限流策略的粒度、层次结构与定制化响应&lt;/h3&gt;&#xA;&lt;p&gt;在实际应用中，灵活的限流服务需要支持精细的粒度和层次化配置模型，以满足不同业务和资源保护的需求。这种配置的优先级机制体现了一种 &lt;strong&gt;“微观精确控制”优于“宏观默认保护”&lt;/strong&gt; 的设计哲学。&lt;/p&gt;&#xA;&lt;p&gt;网关通常支持多层次的限流配置，包括：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;特定 API 或消费者限流：&lt;/strong&gt; 这是优先级最高的限流配置。例如，用户可以对单个关键 API 进行限流设置，或者对特定的消费者群体施加限制。这种配置会覆盖所有默认设置。这意味着在限流值冲突时，系统优先执行最明确定义或最严格的限制，确保关键资源的防护级别不受宏观策略的稀释。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;API 默认限流：&lt;/strong&gt; 作用于应用下大部分 API 的通用配置。当没有针对单个 API 配置限流值时，将采用此默认值。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;应用总限流 (App Total Limit)：&lt;/strong&gt; 这是对当前应用下所有 API 请求的总和设置的上限。应用总限流是防止资源被“虹吸”的最后防线。即使单个 API 的限流都没有达到，一旦应用的总请求量超出限流总和值，所有请求都将被限制。这种设计解决了在微服务架构中，攻击者通过对大量低 QPS API 进行频繁调用，最终耗尽整个应用共享资源预算的“长尾攻击”问题。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;网关在触发限流时，必须向客户端返回明确的、用户友好的响应。例如，默认的限流响应可能包含 &lt;code&gt;{&amp;quot;resultStatus&amp;quot;:1002, &amp;quot;tips&amp;quot;:&amp;quot;顾客太多，客官请稍候&amp;quot;}&lt;/code&gt; 。为了实现友好的降级体验，网关需要支持定制化的响应格式，允许用户配置 JSON 格式的返回内容，如通过 &lt;code&gt;resultStatus&lt;/code&gt; 字段（例如，1002 表示限流）和 &lt;code&gt;tips&lt;/code&gt; 字段向用户提供定制化的限流提示。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2-常见限流算法的原理适用性与分布式性能剖析&#34;&gt;2. 常见限流算法的原理、适用性与分布式性能剖析&lt;/h2&gt;&#xA;&lt;p&gt;选择合适的限流算法是构建高性能网关服务的基石。不同的算法在精确度、突发处理能力和分布式系统中的扩展性方面存在显著差异。&lt;/p&gt;&#xA;&lt;h3 id=&#34;21-固定窗口计数器-fixed-window-counter-fwc&#34;&gt;2.1. 固定窗口计数器 (Fixed Window Counter, FWC)&lt;/h3&gt;&#xA;&lt;p&gt;固定窗口计数器是最简单、资源消耗最低的限流算法。它在一个固定的时间周期内（例如每 60 秒）累积请求计数，当周期结束时，计数器重置。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;优势与局限性：&lt;/strong&gt; FWC 的实现非常简单，查询和递增操作计算复杂度为 $O(1)$，因此延迟极低。然而，其主要局限在于&lt;strong&gt;边界突发问题&lt;/strong&gt;。如果客户端在窗口结束前的一刻发出大量请求，并在下一个窗口开始后的第一时间再次发出同等量的请求，系统在短时间内实际放行的请求量可能高达阈值的两倍。这使得 FWC 难以应对流量的瞬间爆发，可能导致上游服务过载。&lt;/p&gt;</description>
			</item>
			<item>
				<title>常见的大模型 OpenAPI 规范</title>
				<link>https://blog.jinzhi.site/posts/2025-11/%E5%B8%B8%E8%A7%81%E7%9A%84%E5%A4%A7%E6%A8%A1%E5%9E%8B-openapi-%E8%A7%84%E8%8C%83/</link>
				<pubDate>Wed, 05 Nov 2025 21:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-11/%E5%B8%B8%E8%A7%81%E7%9A%84%E5%A4%A7%E6%A8%A1%E5%9E%8B-openapi-%E8%A7%84%E8%8C%83/</guid>
				<description>&lt;p&gt;AI Gateway 的对接开发中，一个重要的内容就是对接不同厂商推理服务的接口协议。目前，推理服务的接口协议主要分为以下几种类型：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;文本对话接口，如 OpenAI 的 chat completions 和 response API 等&lt;/li&gt;&#xA;&lt;li&gt;向量接口，向量接口用于将输入的文本或者图片、视频（多模态）等转换成向量表示，适用于搜索（文搜图、图搜图、图文混合搜索）、聚类、推荐等场景。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;文本对话&#34;&gt;文本对话&lt;/h2&gt;&#xA;&lt;p&gt;文本对话 API 需要提供如下能力支持：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;模型选择&lt;/li&gt;&#xA;&lt;li&gt;用户、系统、模型输入内容角色区分&lt;/li&gt;&#xA;&lt;li&gt;模型参数调整&lt;/li&gt;&#xA;&lt;li&gt;工具调用&lt;/li&gt;&#xA;&lt;li&gt;MCP 支持&lt;/li&gt;&#xA;&lt;li&gt;用量统计&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;目前使用最广泛的文本对话接口自然是 OpenAI 的 chat completions API。几乎所有的 LLM 服务提供商都支持 chat completions compatible 调用。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://platform.openai.com/docs/api-reference/introduction&#34;&gt;https://platform.openai.com/docs/api-reference/introduction&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;chat-completions&#34;&gt;chat completions&lt;/h3&gt;&#xA;&lt;p&gt;基本调用：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;curl https://api.openai.com/v1/chat/completions \&#xA;  -H &amp;#34;Content-Type: application/json&amp;#34; \&#xA;  -H &amp;#34;Authorization: Bearer $OPENAI_API_KEY&amp;#34; \&#xA;  -d &amp;#39;{&#xA;    &amp;#34;model&amp;#34;: &amp;#34;gpt-5&amp;#34;,&#xA;    &amp;#34;messages&amp;#34;: [&#xA;      {&#xA;        &amp;#34;role&amp;#34;: &amp;#34;developer&amp;#34;,&#xA;        &amp;#34;content&amp;#34;: &amp;#34;You are a helpful assistant.&amp;#34;&#xA;      },&#xA;      {&#xA;        &amp;#34;role&amp;#34;: &amp;#34;user&amp;#34;,&#xA;        &amp;#34;content&amp;#34;: &amp;#34;Hello!&amp;#34;&#xA;      }&#xA;    ]&#xA;  }&amp;#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;model: 请求调用的模型&lt;/li&gt;&#xA;&lt;li&gt;messages：构成对话的消息体。根据消息的来源角色，message 可以分为 developer/system（开发者，系统提供的 prompt），user（用户自身的输入）和 assistant（模型的响应，用于多轮对话时模型的上下文传递）。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;content 分为两种类型，纯文本即为 string，非纯文本 content 为列表类型，内容根据 type（text，image_url，input_audio 等）有不同的字段&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;stream：采用正常 HTTP 响应还是 sse 响应&lt;/li&gt;&#xA;&lt;li&gt;stream_options: 在 sse 响应时，有些模型默认不会输出 usage 信息，需要显式将 stream_options.include_usage 设置成 true&lt;/li&gt;&#xA;&lt;li&gt;temperature：模型温度，取值范围 0 - 2，值越高，输出的 tokens 随机性越大&lt;/li&gt;&#xA;&lt;li&gt;top_p：和 tempreature 一样对模型输出进行调整的参数，模型会考虑概率质量最高的top_p个tokens的结果。所以0.1意味着只考虑概率质量最高的10%的tokens。&lt;/li&gt;&#xA;&lt;li&gt;reasoning_effort：模型的推理深度，比如对于 OpenAI 模型来说有 minimal，low，medium，high 等多种选择。&lt;/li&gt;&#xA;&lt;li&gt;max_completion_tokens：最大输出 tokens 数，包括 output tokens 和 reasoning tokens。替代原来的 max_tokens 字段。&lt;/li&gt;&#xA;&lt;li&gt;tools：告知大模型本地可调用的工具列表。工具里面定义了工具的名称、描述和 json schema 表示的参数描述。替代原来的 functions 字段。&lt;/li&gt;&#xA;&lt;li&gt;tool_choice：告知模型对于工具的调用选择。none 表示不要调用任何工具直接生成 messages，auto 表示由模型自己决定是否调用 allowed_tools。required 表示模型必须调用至少一个工具。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;除此之外，各家可以在 OpenAI 标准的 API 上扩展自己的字段，比如 cherry studio 会使用 thinking 字段来开启/关闭模型思考：&lt;/p&gt;</description>
			</item>
			<item>
				<title>APISIX 插件体系</title>
				<link>https://blog.jinzhi.site/posts/2025-10/apisix-%E6%8F%92%E4%BB%B6%E4%BD%93%E7%B3%BB/</link>
				<pubDate>Thu, 30 Oct 2025 12:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-10/apisix-%E6%8F%92%E4%BB%B6%E4%BD%93%E7%B3%BB/</guid>
				<description>&lt;h2 id=&#34;背景知识&#34;&gt;背景知识&lt;/h2&gt;&#xA;&lt;p&gt;APISIX 基于 Openresty 和 Nginx 开发，了解 APISIX 的插件体系也有必要先了解下 Nginx 和 Openresty 的基础知识。&lt;/p&gt;&#xA;&lt;h3 id=&#34;nginx-请求处理阶段&#34;&gt;Nginx 请求处理阶段&lt;/h3&gt;&#xA;&lt;p&gt;Nginx 将一个 HTTP 请求的处理过程精心划分为一系列有序的阶段（Phases），就像一个工厂的流水线。每个阶段都有特定的任务，不同的模块可以将自己的处理程序（handler）注册到感兴趣的阶段。这种设计使得 Nginx 的功能高度模块化、可扩展，并且处理流程非常清晰高效。&lt;/p&gt;&#xA;&lt;p&gt;一个请求在 Nginx 中主要会经过以下 &lt;strong&gt;11 个处理阶段&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;h4 id=&#34;1ngx_http_post_read_phase请求读取后阶段&#34;&gt;1. &lt;code&gt;NGX_HTTP_POST_READ_PHASE&lt;/code&gt; (请求读取后阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 接收到完整的请求头（Request Header）之后，第一个被执行的阶段。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块&lt;/strong&gt;: &lt;code&gt;ngx_http_realip_module&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 在这个阶段，&lt;code&gt;realip&lt;/code&gt; 模块会根据 &lt;code&gt;X-Forwarded-For&lt;/code&gt; 或 &lt;code&gt;X-Real-IP&lt;/code&gt; 等请求头，将客户端的真实 IP 地址替换掉代理服务器的 IP 地址。这对后续的访问控制和日志记录至关重要。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;2ngx_http_server_rewrite_phaseserver-级别地址重写阶段&#34;&gt;2. &lt;code&gt;NGX_HTTP_SERVER_REWRITE_PHASE&lt;/code&gt; (Server 级别地址重写阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 在 &lt;code&gt;server&lt;/code&gt; 配置块中执行 URL 重写。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;rewrite&lt;/code&gt; 指令（当它定义在 &lt;code&gt;server&lt;/code&gt; 块中时）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 在请求进入具体的 &lt;code&gt;location&lt;/code&gt; 匹配之前，对 URL 进行全局的、初步的改写。例如，将所有 &lt;code&gt;http&lt;/code&gt; 请求强制重定向到 &lt;code&gt;https&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;listen&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;server_name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;example.com&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 这个 rewrite 就工作在 SERVER_REWRITE 阶段&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;rewrite&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;^/(.*)&lt;/span&gt;$ &lt;span class=&#34;s&#34;&gt;https://example.com/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;permanent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;3ngx_http_find_config_phase配置查找阶段&#34;&gt;3. &lt;code&gt;NGX_HTTP_FIND_CONFIG_PHASE&lt;/code&gt; (配置查找阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 根据上个阶段处理完的 URI，查找并匹配对应的 &lt;code&gt;location&lt;/code&gt; 配置块。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;核心功能&lt;/strong&gt;: 这是 Nginx 路由的核心。Nginx 会用请求的 URI 与 &lt;code&gt;location&lt;/code&gt; 指令定义的规则进行匹配，找到最合适的 &lt;code&gt;location&lt;/code&gt;。这个阶段没有模块可以注册 handler，是 Nginx 核心自己完成的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;4ngx_http_rewrite_phaselocation-级别地址重写阶段&#34;&gt;4. &lt;code&gt;NGX_HTTP_REWRITE_PHASE&lt;/code&gt; (Location 级别地址重写阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 在上一步匹配到的 &lt;code&gt;location&lt;/code&gt; 块内部，执行 URL 重写。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;rewrite&lt;/code&gt; 指令（当它定义在 &lt;code&gt;location&lt;/code&gt; 块中时）、&lt;code&gt;set&lt;/code&gt; 指令。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 对特定 &lt;code&gt;location&lt;/code&gt; 的请求进行更精细的 URL 改写。这个阶段的 &lt;code&gt;rewrite&lt;/code&gt; 可能会导致 Nginx 重新回到 &lt;code&gt;FIND_CONFIG&lt;/code&gt; 阶段去匹配新的 &lt;code&gt;location&lt;/code&gt;，可能会有循环，最多执行 10 次以防止死循环。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/app/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 这个 rewrite 工作在 REWRITE 阶段&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;rewrite&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;^/app/(.*)&lt;/span&gt;$ &lt;span class=&#34;s&#34;&gt;/v2/app/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;5ngx_http_post_rewrite_phase地址重写后阶段&#34;&gt;5. &lt;code&gt;NGX_HTTP_POST_REWRITE_PHASE&lt;/code&gt; (地址重写后阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 防止 &lt;code&gt;rewrite&lt;/code&gt; 阶段的重写指令导致死循环。如果 URI 在上一个阶段被重写，这个阶段会把重写后的 URI 交给 Nginx，让其重新开始 &lt;code&gt;FIND_CONFIG&lt;/code&gt; 阶段，查找新的 &lt;code&gt;location&lt;/code&gt;。这是一个内部阶段，用户通常不直接感知。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;6ngx_http_preaccess_phase访问权限控制前置阶段&#34;&gt;6. &lt;code&gt;NGX_HTTP_PREACCESS_PHASE&lt;/code&gt; (访问权限控制前置阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 在正式的访问权限检查之前，做一些准备工作。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块&lt;/strong&gt;: &lt;code&gt;ngx_http_limit_conn_module&lt;/code&gt; (连接数限制), &lt;code&gt;ngx_http_limit_req_module&lt;/code&gt; (请求速率限制)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 在检查用户名密码之前，先检查客户端的请求速率是否过快，如果过快，直接拒绝，不必再执行后面的阶段。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;7ngx_http_access_phase访问权限控制阶段&#34;&gt;7. &lt;code&gt;NGX_HTTP_ACCESS_PHASE&lt;/code&gt; (访问权限控制阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 对请求进行权限验证。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;ngx_http_access_module&lt;/code&gt; (&lt;code&gt;allow&lt;/code&gt;, &lt;code&gt;deny&lt;/code&gt;), &lt;code&gt;ngx_http_auth_basic_module&lt;/code&gt; (HTTP 基本认证)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 检查客户端 IP 是否在允许列表中，或者验证用户提供的用户名和密码是否正确。如果这个阶段有任何模块拒绝了请求，处理就会立即中断并返回错误（如 403 Forbidden）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;8ngx_http_post_access_phase访问权限控制后置阶段&#34;&gt;8. &lt;code&gt;NGX_HTTP_POST_ACCESS_PHASE&lt;/code&gt; (访问权限控制后置阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 主要用于配合 &lt;code&gt;ACCESS&lt;/code&gt; 阶段的 &lt;code&gt;satisfy&lt;/code&gt; 指令。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 当 &lt;code&gt;satisfy any;&lt;/code&gt; 被使用时，如果 &lt;code&gt;ACCESS&lt;/code&gt; 阶段有模块允许了访问（例如 IP 匹配成功），&lt;code&gt;POST_ACCESS&lt;/code&gt; 阶段的处理就可以被跳过。如果 &lt;code&gt;ACCESS&lt;/code&gt; 阶段没有明确允许，这个阶段的处理（例如 HTTP 基本认证）就会被执行。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;9ngx_http_try_files_phasetry_files-阶段&#34;&gt;9. &lt;code&gt;NGX_HTTP_TRY_FILES_PHASE&lt;/code&gt; (Try_files 阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: &lt;code&gt;try_files&lt;/code&gt; 指令专属的特殊阶段。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;try_files&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举例&lt;/strong&gt;: 按顺序检查文件或目录是否存在，如果找到，则内部重定向到该文件，如果都找不到，则执行最后一个参数（通常是内部重定向到一个 &lt;code&gt;location&lt;/code&gt; 或返回一个状态码）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 这个指令工作在 TRY_FILES 阶段&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;try_files&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$uri&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$uri/&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/index.html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;10ngx_http_content_phase内容生成阶段&#34;&gt;10. &lt;code&gt;NGX_HTTP_CONTENT_PHASE&lt;/code&gt; (内容生成阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: &lt;strong&gt;核心阶段&lt;/strong&gt;，负责生成最终的响应内容并发送给客户端。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;重要特性&lt;/strong&gt;: 每个 &lt;code&gt;location&lt;/code&gt; 只有一个模块能成为“内容处理模块”（Content Handler）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块&lt;/strong&gt;:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;ngx_http_static_module&lt;/code&gt;: 处理静态文件。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;ngx_http_proxy_module&lt;/code&gt;: 将请求反向代理到后端服务器 (&lt;code&gt;proxy_pass&lt;/code&gt;)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;ngx_http_fastcgi_module&lt;/code&gt;: 将请求转发给 FastCGI 应用（如 PHP-FPM）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;ngx_http_index_module&lt;/code&gt;: 处理目录索引文件。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;return&lt;/code&gt;: 直接返回指定的状态码或内容。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;执行逻辑&lt;/strong&gt;: Nginx 会调用在 &lt;code&gt;location&lt;/code&gt; 中找到的内容处理模块。例如，如果配置了 &lt;code&gt;proxy_pass&lt;/code&gt;，那么 &lt;code&gt;proxy_module&lt;/code&gt; 就会接管请求。如果没有特定的内容处理模块，默认会由 &lt;code&gt;static_module&lt;/code&gt; 尝试提供静态文件服务。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;11ngx_http_log_phase日志记录阶段&#34;&gt;11. &lt;code&gt;NGX_HTTP_LOG_PHASE&lt;/code&gt; (日志记录阶段)&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;: 请求处理完成后，记录访问日志。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常用模块/指令&lt;/strong&gt;: &lt;code&gt;ngx_http_log_module&lt;/code&gt; (&lt;code&gt;access_log&lt;/code&gt;)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;作用举-例&lt;/strong&gt;: 无论请求成功还是失败，这个阶段都会被执行（除非有严重错误），用于将请求的相关信息（如客户端IP、请求时间、状态码等）写入到日志文件中。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;过滤器模块-filter-modules&#34;&gt;过滤器模块 (Filter Modules)&lt;/h4&gt;&#xA;&lt;p&gt;当 &lt;code&gt;CONTENT&lt;/code&gt; 阶段生成了响应内容后，在发送给客户端之前，响应数据还会经过一系列的 &lt;strong&gt;过滤器（Filter）&lt;/strong&gt; 链处理。过滤器负责对响应头和响应体进行修改或加工。&lt;/p&gt;</description>
			</item>
			<item>
				<title>WebSocket Origin Header 校验失败</title>
				<link>https://blog.jinzhi.site/posts/2025-10/websocket-origin-header-%E6%A0%A1%E9%AA%8C%E5%A4%B1%E8%B4%A5/</link>
				<pubDate>Tue, 21 Oct 2025 15:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-10/websocket-origin-header-%E6%A0%A1%E9%AA%8C%E5%A4%B1%E8%B4%A5/</guid>
				<description>&lt;p&gt;最近做 APISIX 线上服务时遇到一个场景：业务使用 websocket 转发时，在浏览器会出现 WebSocket close with status code 1006 的错误。打开调试工具查看发现在 websocket 握手时服务端返回了 403。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/websocket-origin-header-%E6%A0%A1%E9%AA%8C%E5%A4%B1%E8%B4%A5/76f75e967736245ec923202987a22482_MD5.jpeg&#34; alt=&#34;76f75e967736245ec923202987a22482_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/websocket-origin-header-%E6%A0%A1%E9%AA%8C%E5%A4%B1%E8%B4%A5/4efbf4b7a2093ed4f1d6e522139dc92e_MD5.jpeg&#34; alt=&#34;4efbf4b7a2093ed4f1d6e522139dc92e_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;非常奇怪的是，如果业务不经过 APISIX 直接访问后端 code-server 是没有问题的（中间也得经过一层 Ingress 转发）。&lt;/p&gt;&#xA;&lt;p&gt;简单的流量模型如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;                                                                                                                      &#xA;                                                                                                                      &#xA;                               +--------------+                              +--------------+          +-------------+&#xA;  https://domain.com:9443/xxx  |              |  http://domain.com:23480/xxx |              |          |             |&#xA;--------------------------------   APISIX     -------------------------------+   Ingress    -----------+ code-server |&#xA;                               |              |                              |              |          |             |&#xA;                               +--------------+                              +--------------+          +-------------+&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;经过对比发现，两者的请求头里面 Host 和 Origin 是存在差异的。尝试在 APISIX 中强制修改 Host 头部，问题没有解决。然后利用 proxy-rewrite 强制修改 Origin 头部，请求恢复正常。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;plugins&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;proxy-rewrite&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uri&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/anything&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;headers&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;#34;set&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;Origin&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http://domain.com&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么问题来了，为什么改完 Origin Header 就行了？code-server 是如何处理 Origin Header 的？为什么 Ingress 可以，APISIX 不行？&lt;/p&gt;</description>
			</item>
			<item>
				<title>Introducing Kubernetes Gateway API</title>
				<link>https://blog.jinzhi.site/posts/2025-10/introducing-kubernetes-gateway-api/</link>
				<pubDate>Thu, 16 Oct 2025 16:18:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-10/introducing-kubernetes-gateway-api/</guid>
				<description>&lt;p&gt;Kubernetes Gateway API 是一个由 SIG-Network 孵化和维护的 &lt;strong&gt;开放、标准、可扩展的 API&lt;/strong&gt;，旨在为 Kubernetes 集群内部和外部的统一流量管理提供更强大、更灵活、更具表现力的方式。&lt;/p&gt;&#xA;&lt;p&gt;它被视为 &lt;strong&gt;Ingress API 的继任者和演进&lt;/strong&gt;，解决了 Ingress 在灵活性、可扩展性、角色分离和 L4-L7 支持方面的诸多局限性。Gateway API 不仅仅关注 HTTP 流量，还支持 TCP、UDP 以及 TLS 路由，覆盖了更广泛的网络场景。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么需要-gateway-api&#34;&gt;为什么需要 Gateway API&lt;/h2&gt;&#xA;&lt;p&gt;在 Gateway API 出现之前，Kubernetes 主要使用 &lt;code&gt;Ingress&lt;/code&gt; 来管理集群的 L7 HTTP/HTTPS 流量。然而，Ingress 存在一些固有的局限性，促使了 Gateway API 的诞生：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;功能有限：&lt;/strong&gt; Ingress 本身功能非常基础，只支持主机和路径路由。任何高级功能（如流量拆分、重写、限速、认证等）都必须通过特定于 Ingress 控制器（如 NGINX Ingress, Traefik, AWS ALB Ingress 等）的 &lt;strong&gt;注解（Annotations）&lt;/strong&gt; 来实现。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;可移植性差：&lt;/strong&gt; 注解是特定于实现的，这意味着用 NGINX Ingress 注解编写的规则无法直接移植到 Traefik 或其他 Ingress 控制器上，造成供应商锁定。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;缺乏角色分离：&lt;/strong&gt; Ingress 资源将网络基础设施的配置（例如暴露的端口、TLS 证书）与应用程序的路由规则混在一起，这使得集群管理员和应用开发者之间的职责难以清晰划分。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;L4 流量支持不足：&lt;/strong&gt; Ingress 仅专注于 HTTP/HTTPS (L7) 流量。对于 TCP、UDP 或 TLS 直通（Passthrough）等 L4 流量，通常需要使用 &lt;code&gt;LoadBalancer&lt;/code&gt; 类型的 Service 或其他的解决方案。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;表达能力有限：&lt;/strong&gt; 难以表达复杂的路由策略，如基于请求头、查询参数的匹配，细粒度的流量权重分配等。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Gateway API 旨在解决这些问题，提供一个更加健壮和通用的流量管理框架。&lt;/p&gt;</description>
			</item>
			<item>
				<title>Go 汇编分析</title>
				<link>https://blog.jinzhi.site/posts/2025-09/go-%E6%B1%87%E7%BC%96%E5%88%86%E6%9E%90/</link>
				<pubDate>Wed, 17 Sep 2025 21:45:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-09/go-%E6%B1%87%E7%BC%96%E5%88%86%E6%9E%90/</guid>
				<description>&lt;p&gt;Go的汇编不是像 C/C++ 一样，对机器码的直接描述，而是兼容跨平台需求实现的半抽象化的指令集。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://go.dev/doc/asm&#34;&gt;https://go.dev/doc/asm&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;汇编分析go-117&#34;&gt;汇编分析（Go 1.17）&lt;/h2&gt;&#xA;&lt;p&gt;我们用一个简单的例子来开始汇编分析：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;汇编结果，删去了一些无关的输出：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# go tool compile -S -l -N main.go&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.main STEXT &lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;54&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x0 &lt;span class=&#34;nv&#34;&gt;locals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x18 &lt;span class=&#34;nv&#34;&gt;funcid&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0000 &lt;span class=&#34;m&#34;&gt;00000&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        TEXT    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.main&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, ABIInternal, &lt;span class=&#34;nv&#34;&gt;$24&lt;/span&gt;-0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0000 &lt;span class=&#34;m&#34;&gt;00000&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        CMPQ    SP, 16&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;R14&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0004 &lt;span class=&#34;m&#34;&gt;00004&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        PCDATA  &lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;$-&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0004 &lt;span class=&#34;m&#34;&gt;00004&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        JLS     &lt;span class=&#34;m&#34;&gt;47&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0006 &lt;span class=&#34;m&#34;&gt;00006&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        PCDATA  &lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;$-&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0006 &lt;span class=&#34;m&#34;&gt;00006&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        SUBQ    &lt;span class=&#34;nv&#34;&gt;$24&lt;/span&gt;, SP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x000a &lt;span class=&#34;m&#34;&gt;00010&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVQ    BP, 16&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x000f &lt;span class=&#34;m&#34;&gt;00015&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        LEAQ    16&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, BP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0014 &lt;span class=&#34;m&#34;&gt;00020&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        FUNCDATA        &lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;, gclocals·33cdeccccebe80329f1fdbee7f5874cb&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0014 &lt;span class=&#34;m&#34;&gt;00020&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        FUNCDATA        &lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;, gclocals·33cdeccccebe80329f1fdbee7f5874cb&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0014 &lt;span class=&#34;m&#34;&gt;00020&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:4&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVL    &lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;, AX&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0019 &lt;span class=&#34;m&#34;&gt;00025&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:4&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVL    &lt;span class=&#34;nv&#34;&gt;$3&lt;/span&gt;, BX&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x001e &lt;span class=&#34;m&#34;&gt;00030&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:4&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        PCDATA  &lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x001e &lt;span class=&#34;m&#34;&gt;00030&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:4&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        NOP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0020 &lt;span class=&#34;m&#34;&gt;00032&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:4&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        CALL    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.add&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0025 &lt;span class=&#34;m&#34;&gt;00037&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVQ    16&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, BP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x002a &lt;span class=&#34;m&#34;&gt;00042&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        ADDQ    &lt;span class=&#34;nv&#34;&gt;$24&lt;/span&gt;, SP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x002e &lt;span class=&#34;m&#34;&gt;00046&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        RET&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x002f &lt;span class=&#34;m&#34;&gt;00047&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        NOP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x002f &lt;span class=&#34;m&#34;&gt;00047&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        PCDATA  &lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;$-&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x002f &lt;span class=&#34;m&#34;&gt;00047&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        PCDATA  &lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;$-&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x002f &lt;span class=&#34;m&#34;&gt;00047&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        CALL    runtime.morestack_noctxt&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0034 &lt;span class=&#34;m&#34;&gt;00052&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        PCDATA  &lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;$-&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0034 &lt;span class=&#34;m&#34;&gt;00052&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        JMP     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.add STEXT nosplit &lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;56&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x10 &lt;span class=&#34;nv&#34;&gt;locals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x10 &lt;span class=&#34;nv&#34;&gt;funcid&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0000 &lt;span class=&#34;m&#34;&gt;00000&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        TEXT    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.add&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, NOSPLIT&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;ABIInternal, &lt;span class=&#34;nv&#34;&gt;$16&lt;/span&gt;-16&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0000 &lt;span class=&#34;m&#34;&gt;00000&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        SUBQ    &lt;span class=&#34;nv&#34;&gt;$16&lt;/span&gt;, SP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0004 &lt;span class=&#34;m&#34;&gt;00004&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVQ    BP, 8&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0009 &lt;span class=&#34;m&#34;&gt;00009&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        LEAQ    8&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, BP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x000e &lt;span class=&#34;m&#34;&gt;00014&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        FUNCDATA        &lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;, gclocals·33cdeccccebe80329f1fdbee7f5874cb&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x000e &lt;span class=&#34;m&#34;&gt;00014&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        FUNCDATA        &lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;, gclocals·33cdeccccebe80329f1fdbee7f5874cb&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x000e &lt;span class=&#34;m&#34;&gt;00014&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        FUNCDATA        &lt;span class=&#34;nv&#34;&gt;$5&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.add.arginfo1&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x000e &lt;span class=&#34;m&#34;&gt;00014&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVQ    AX, &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.i+24&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0013 &lt;span class=&#34;m&#34;&gt;00019&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVQ    BX, &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.j+32&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0018 &lt;span class=&#34;m&#34;&gt;00024&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:7&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVQ    &lt;span class=&#34;nv&#34;&gt;$0&lt;/span&gt;, &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.~r2&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0020 &lt;span class=&#34;m&#34;&gt;00032&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVQ    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.i+24&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, AX&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0025 &lt;span class=&#34;m&#34;&gt;00037&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        ADDQ    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.j+32&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, AX&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x002a &lt;span class=&#34;m&#34;&gt;00042&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVQ    AX, &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;.~r2&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x002e &lt;span class=&#34;m&#34;&gt;00046&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        MOVQ    8&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;SP&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, BP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0033 &lt;span class=&#34;m&#34;&gt;00051&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        ADDQ    &lt;span class=&#34;nv&#34;&gt;$16&lt;/span&gt;, SP&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        0x0037 &lt;span class=&#34;m&#34;&gt;00055&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;main.go:8&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        RET&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;FUNCDATA&lt;/code&gt;和&lt;code&gt;PCDATA&lt;/code&gt;是由编译器引入的，主要包含垃圾回收时使用的信息，这里略过。&lt;/p&gt;</description>
			</item>
			<item>
				<title>Lua：Table 浅析</title>
				<link>https://blog.jinzhi.site/posts/2025-09/luatable-%E6%B5%85%E6%9E%90/</link>
				<pubDate>Sun, 14 Sep 2025 23:45:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-09/luatable-%E6%B5%85%E6%9E%90/</guid>
				<description>&lt;p&gt;本文的分析基于 OpenResty 的 Lua 分支（https://github.com/openresty/luajit2）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;核心-api&#34;&gt;核心 API&lt;/h2&gt;&#xA;&lt;p&gt;table 的 API 定义在 src/lib_table.c 中，API 分为三个部分：&lt;/p&gt;&#xA;&lt;p&gt;标准库函数：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;table.insert() - 向 table 插入元素&lt;/li&gt;&#xA;&lt;li&gt;table.remove() - 移除 table 元素&lt;/li&gt;&#xA;&lt;li&gt;table.concat() - 连接 table 元素为字符串&lt;/li&gt;&#xA;&lt;li&gt;table.sort() - 对 table 进行排序&lt;/li&gt;&#xA;&lt;li&gt;table.maxn() - 找到 table 中最大数字键&lt;/li&gt;&#xA;&lt;li&gt;table.move() - 移动 table 元素&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;LuaJIT 扩展函数：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;table.new() - 预分配指定大小的 table&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;OpenResty 扩展函数：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;table.clear() - 清空 table 内容&lt;/li&gt;&#xA;&lt;li&gt;table.clone() - 克隆 table&lt;/li&gt;&#xA;&lt;li&gt;table.nkeys() - 获取 table 键的数量&lt;/li&gt;&#xA;&lt;li&gt;table.isarray() - 检查是否为数组&lt;/li&gt;&#xA;&lt;li&gt;table.isempty() - 检查 table 是否为空&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;数据结构&#34;&gt;数据结构&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Node&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;TValue&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// 值对象，必须是第一个字段&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;TValue&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// 键对象&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;MRef&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;          &lt;span class=&#34;c1&#34;&gt;// 哈希链指针&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#if !LJ_GC64&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;MRef&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;freetop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 32位架构下的空闲节点顶部指针(存储在node[0])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GCtab&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;GCHeader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;// GC 通用头部：nextgc, marked, gct&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nomm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 元方法负缓存掩码&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;int8_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;colo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 数组共址标记 (-1表示已分离, &amp;gt;0表示共址大小)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;MRef&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// 数组部分指针&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;GCRef&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gclist&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// GC 链表指针&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;GCRef&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;metatable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 元表引用&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;MRef&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;          &lt;span class=&#34;c1&#34;&gt;// 哈希部分指针&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;// 数组部分大小 [0, asize-1]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;// 哈希掩码 (哈希部分大小-1)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#if LJ_GC64&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;MRef&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;freetop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 64位架构下的空闲节点顶部指针&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GCtab&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到，GCtab 中同时定义了数组部分 &lt;code&gt;array&lt;/code&gt; 和哈希部分 &lt;code&gt;node&lt;/code&gt;。&lt;/p&gt;</description>
			</item>
			<item>
				<title>Lua：Concurrency</title>
				<link>https://blog.jinzhi.site/posts/2025-09/luaconcurrency/</link>
				<pubDate>Mon, 01 Sep 2025 00:27:09 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-09/luaconcurrency/</guid>
				<description>&lt;p&gt;Lua 的并发（Concurrency）设计核心在于其轻量级、嵌入式的哲学，以及对协作式多任务的首选。它通过强大的协程机制实现并发，但本身不提供多线程/多进程的并行能力。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;多线程多进程&#34;&gt;多线程/多进程&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;核心语言无内置支持：&lt;/strong&gt; Lua 语言本身的核心 VM 被设计为&lt;strong&gt;单线程&lt;/strong&gt;执行。它不提供内置的语法或标准库来直接创建和管理线程（&lt;code&gt;std::thread&lt;/code&gt;）或进程（&lt;code&gt;fork&lt;/code&gt;）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;独立的 Lua State：&lt;/strong&gt; 一个 Lua VM 实例被称为一个“Lua State”。每个 Lua State 是完全独立的运行时环境，拥有自己的全局变量、栈、打开的文件、垃圾回收器等。它们之间默认不共享任何数据。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;宿主语言的责任：&lt;/strong&gt; 如果需要在 Lua 中实现真正的并行（多核利用），必须依赖于&lt;strong&gt;宿主语言（如 C/C++）的多线程/多进程机制&lt;/strong&gt;。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;实现方式：&lt;/strong&gt; 在宿主语言的每个线程或进程中，创建并运行一个&lt;strong&gt;独立的 Lua State&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;数据交换：&lt;/strong&gt; 这些独立的 Lua State 之间无法直接共享内存。数据交换必须通过宿主语言提供的进程间通信 (IPC) 或线程间通信 (ITC) 机制（如消息队列、共享内存、管道、套接字等）来完成。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;优点：&lt;/strong&gt; 简单安全，因为 Lua State 之间是隔离的，避免了复杂的并发同步问题。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;缺点：&lt;/strong&gt; 额外的通信开销和复杂性，且无法在单个 Lua State 内部实现并行。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;第三方库（封装）：&lt;/strong&gt; 存在一些第三方库（如 LuaLanes）试图提供在 Lua 中模拟多线程/多进程的 API。这些库通常是在底层创建独立的 Lua State，并封装了 IPC 机制，方便 Lua 开发者使用，但其本质仍然是基于宿主语言的底层能力和独立的 Lua State。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;协程&#34;&gt;协程&lt;/h2&gt;&#xA;&lt;h3 id=&#34;协程的设计与实现&#34;&gt;协程的设计与实现&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;设计理念：&lt;/strong&gt; Lua 协程是为了提供&lt;strong&gt;协作式多任务 (Cooperative Multitasking)&lt;/strong&gt; 而设计。它们允许在单个线程中实现任务的暂停和恢复，以模拟并发，而无需复杂的锁机制。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;“有栈协程” (Stackful Coroutines)：&lt;/strong&gt; Lua 协程是&lt;strong&gt;有栈的&lt;/strong&gt;。这里的“栈”指的不是操作系统的 C 语言栈，而是 Lua 虚拟机内部维护的&lt;strong&gt;Lua VM 栈&lt;/strong&gt;。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Lua VM 栈：&lt;/strong&gt; 每个协程在创建时都会分配一个独立的 Lua VM 栈（或在需要时动态扩展）。这个栈存储着协程的局部变量、函数参数、中间表达式结果和函数调用上下文。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;实现机制：&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;coroutine.create(function)&lt;/code&gt;：&lt;/strong&gt; 创建一个新的协程（一个&lt;code&gt;thread&lt;/code&gt;类型的值），但并不立即执行。它会分配并初始化一个新的 Lua VM 栈。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;coroutine.yield(...)&lt;/code&gt; (保存栈)：&lt;/strong&gt; 当一个协程调用 &lt;code&gt;yield&lt;/code&gt; 时，Lua VM 会：&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;保存当前 Lua VM 栈的完整状态&lt;/strong&gt;（包括所有活跃的栈帧、局部变量值、程序计数器等）。这些信息会被存储在协程对象本身（在堆上分配）中。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;暂停当前协程的执行。&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;将控制权返回给调用 &lt;code&gt;coroutine.resume&lt;/code&gt; 的那个协程或主线程。&lt;/strong&gt; C 语言栈会正常展开，&lt;code&gt;yield&lt;/code&gt; 作为一个 C 函数正常返回。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;coroutine.resume(co, ...)&lt;/code&gt; (恢复栈)：&lt;/strong&gt; 当一个协程被 &lt;code&gt;resume&lt;/code&gt; 时，Lua VM 会：&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;从协程对象中加载并恢复其之前保存的 Lua VM 栈状态。&lt;/strong&gt; 这包括设置栈顶指针、恢复所有栈帧和程序计数器，使得协程能够从上次 &lt;code&gt;yield&lt;/code&gt; 的点继续执行。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;将控制权转移给被恢复的协程。&lt;/strong&gt; C 语言栈上会为 &lt;code&gt;resume&lt;/code&gt; 函数创建一个新的栈帧，并在其中运行被恢复的 Lua 协程。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;优点：&lt;/strong&gt; 简单、高效、避免了与 OS 栈相关的复杂性，并且由于是协作式的，没有竞态条件和锁的开销。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;缺点：&lt;/strong&gt; 无法利用多核 CPU。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;协程示例：&lt;/p&gt;</description>
			</item>
			<item>
				<title>Lua - An Overview</title>
				<link>https://blog.jinzhi.site/posts/2025-08/lua-an-overview/</link>
				<pubDate>Sun, 31 Aug 2025 13:29:48 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-08/lua-an-overview/</guid>
				<description>&lt;h2 id=&#34;lua-和-luajit&#34;&gt;Lua 和 LuaJIT&lt;/h2&gt;&#xA;&lt;h3 id=&#34;lua&#34;&gt;Lua&lt;/h3&gt;&#xA;&lt;p&gt;Lua 是一个开源项目，由巴西里约热内卢天主教大学的 Roberto Ierusalimschy、Luiz Henrique de Figueiredo 和 Waldemar Celes 创建。它的版本控制相对简单明了。&lt;/p&gt;&#xA;&lt;h4 id=&#34;lua-的版本体系&#34;&gt;Lua 的版本体系&lt;/h4&gt;&#xA;&lt;p&gt;Lua 的版本号通常是 &lt;code&gt;X.Y&lt;/code&gt; 的形式，例如 &lt;code&gt;5.1&lt;/code&gt;, &lt;code&gt;5.2&lt;/code&gt;, &lt;code&gt;5.3&lt;/code&gt;, &lt;code&gt;5.4&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;X&lt;/code&gt; (主版本号/Major Version):&lt;/strong&gt; 表示一个&lt;strong&gt;重大更新&lt;/strong&gt;，通常会引入不兼容的更改（breaking changes），新的核心特性，或者对虚拟机架构的显著改进。从 &lt;code&gt;5.x&lt;/code&gt; 到 &lt;code&gt;5.y&lt;/code&gt;，&lt;code&gt;y&lt;/code&gt; 增加通常意味着语法、API 或语义的更改，可能需要修改现有代码。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;例子:&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Lua 5.0:&lt;/strong&gt; 引入了协程 (coroutines)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Lua 5.1:&lt;/strong&gt; 引入了模块系统 (module system)、&lt;code&gt;vararg&lt;/code&gt; 参数的改进。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Lua 5.2:&lt;/strong&gt; 引入了 &lt;code&gt;goto&lt;/code&gt; 语句、环境 (environments) 的重新设计、新的 &lt;code&gt;_ENV&lt;/code&gt; 上值。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Lua 5.3:&lt;/strong&gt; 引入了整数类型、位操作 (bitwise operations)、UTF-8 支持。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Lua 5.4:&lt;/strong&gt; 引入了新的垃圾回收器、弱表 (weak tables) 的改进。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;Y&lt;/code&gt; (次版本号/Minor Version) 或补丁版本 (Patch Version):&lt;/strong&gt; 在主版本中，通常用于表示错误修复、性能优化或次要的功能增强。这些更改通常是&lt;strong&gt;向后兼容&lt;/strong&gt;的（backward compatible），不会破坏现有代码运行。有时候，一个版本号会是 &lt;code&gt;X.Y.Z&lt;/code&gt; 的形式，&lt;code&gt;Z&lt;/code&gt; 就代表补丁版本。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;例子:&lt;/strong&gt; &lt;code&gt;Lua 5.3.1&lt;/code&gt;, &lt;code&gt;Lua 5.3.2&lt;/code&gt;, &lt;code&gt;Lua 5.3.3&lt;/code&gt; 等等。这些通常是修复 bug。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h3 id=&#34;luajit&#34;&gt;LuaJIT&lt;/h3&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/LuaJIT/LuaJIT&#34;&gt;https://github.com/LuaJIT/LuaJIT&lt;/a&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Wasm Internals: Stack Machine</title>
				<link>https://blog.jinzhi.site/posts/2025-08/wasm-internals-stack-machine/</link>
				<pubDate>Wed, 20 Aug 2025 01:04:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-08/wasm-internals-stack-machine/</guid>
				<description>&lt;p&gt;Wasm 中的“栈机”（Stack Machine），这正是其核心执行模型之一。Wasm 是一种基于栈的虚拟机，这意味着它的所有操作都通过从一个操作数栈中弹出值、执行操作并将结果压回栈中来完成。它没有传统的“寄存器”概念。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是栈机&#34;&gt;什么是栈机？&lt;/h2&gt;&#xA;&lt;p&gt;在计算机科学中，栈机是一种计算模型，其中指令操作数被隐含地从一个被称为“操作数栈”的内存区域中获取，并且结果被隐含地压回这个栈。这种模型与基于寄存器或基于累加器的模型形成对比。&lt;/p&gt;&#xA;&lt;h2 id=&#34;wasm-栈机的工作原理&#34;&gt;Wasm 栈机的工作原理&lt;/h2&gt;&#xA;&lt;p&gt;Wasm 模块中的函数是由一系列指令组成的。这些指令会操作一个中央的操作数栈。&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;操作数栈（Operand Stack）&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;这是 Wasm 执行函数时最核心的数据结构。&lt;/li&gt;&#xA;&lt;li&gt;所有的操作数（如整数、浮点数）和操作结果都临时存储在这个栈上。&lt;/li&gt;&#xA;&lt;li&gt;指令不会像在注册机中那样直接指定操作数的位置（如“将 R1 的值加到 R2”）。相反，它们会假定操作数已经在栈的顶部。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;局部变量（Local Variables）&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;除了操作数栈，每个函数调用还有一个独立的“局部变量”区域。&lt;/li&gt;&#xA;&lt;li&gt;局部变量是命名的存储位置，可以在函数的整个执行过程中被访问和修改。&lt;/li&gt;&#xA;&lt;li&gt;虽然局部变量不是栈的一部分，但有很多指令允许你将局部变量的值压入栈中，或者将栈顶部的值存储到局部变量中。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;参数（Parameters）&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;函数的参数在函数被调用时，会被初始化为局部变量的一部分（通常是前几个局部变量）。&lt;/li&gt;&#xA;&lt;li&gt;它们也可以被认为是函数执行上下文的一部分。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;指令的操作&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;压栈（Push）&lt;/strong&gt;：很多指令会将值压入栈中。例如：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;i32.const 42&lt;/code&gt;：将整数常量 &lt;code&gt;42&lt;/code&gt; 压入栈。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;local.get &amp;lt;idx&amp;gt;&lt;/code&gt;：获取索引为 &lt;code&gt;&amp;lt;idx&amp;gt;&lt;/code&gt; 的局部变量的值并压入栈。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;弹栈（Pop）&lt;/strong&gt;：大多数操作指令会从栈顶弹出所需数量的操作数。例如：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;i32.add&lt;/code&gt;：弹出栈顶的两个 &lt;code&gt;i32&lt;/code&gt; 整数，将它们相加，然后将结果压回栈。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;if&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt;/&lt;code&gt;loop&lt;/code&gt; 等控制流指令的条件值也会从栈中弹出。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;复合操作&lt;/strong&gt;：一些指令可能弹出一个值，执行一些副作用（如内存写入），而不压入任何新值。例如：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;i32.store&lt;/code&gt;：弹出内存地址和要存储的值，将值写入内存。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;栈机模型的优势与特点&#34;&gt;栈机模型的优势与特点&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;紧凑性（Compactness）&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;指令更短，因为它们不需要编码操作数的位置。例如，一个加法操作，在寄存器机中可能需要指定两个源寄存器和一个目标寄存器；在栈机中，它只是一个简单的 &lt;code&gt;add&lt;/code&gt; 指令。&lt;/li&gt;&#xA;&lt;li&gt;这有助于生成更小的二进制代码，对于 Web 环境中的快速下载和解析非常有利。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;简化编译器后端（Simplified Compiler Backends）&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;IR（中间表示）到指令的映射通常更直接。许多高级语言的语义本身就可以很容易地映射到栈操作。&lt;/li&gt;&#xA;&lt;li&gt;这使得将 C/C++/Rust 等语言编译到 Wasm 变得相对容易。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;易于验证（Easy to Validate）&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Wasm 在加载时会进行严格的类型检查和结构验证。栈机模型使得验证其类型安全变得相对容易。例如，当检查 &lt;code&gt;i32.add&lt;/code&gt; 指令时，验证器只需确保栈顶有两个 &lt;code&gt;i32&lt;/code&gt; 类型的值。&lt;/li&gt;&#xA;&lt;li&gt;这对于沙盒环境中的安全性至关重要。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;独立于目标架构（Architecture-Independent）&lt;/strong&gt;：&lt;/p&gt;</description>
			</item>
			<item>
				<title>Kubernetes CSI 简介</title>
				<link>https://blog.jinzhi.site/posts/2025-06/kubernetes-csi-%E7%AE%80%E4%BB%8B/</link>
				<pubDate>Tue, 24 Jun 2025 09:57:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-06/kubernetes-csi-%E7%AE%80%E4%BB%8B/</guid>
				<description>&lt;p&gt;K8s CSI 是 Kubernetes 中非常重要的一个组件，它解决了存储与计算分离的复杂性，并为容器化应用提供了持久化存储的能力。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1-基本概念&#34;&gt;1. 基本概念&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;CSI (Container Storage Interface)&lt;/strong&gt; 译为 &lt;strong&gt;容器存储接口&lt;/strong&gt;。它是由 Kubernetes 社区与存储厂商共同制定的一套标准接口规范。&lt;/p&gt;&#xA;&lt;p&gt;在 CSI 出现之前，Kubernetes 存储插件的开发和管理存在以下痛点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;紧耦合问题：&lt;/strong&gt; Kubernetes 内部集成了大量的存储驱动（In-tree 存储插件），例如 AWS EBS、GCE PD、Azure Disk、Ceph RBD 等。这意味着每当存储厂商需要支持 Kubernetes 时，他们都必须将其存储驱动代码提交到 Kubernetes 的核心代码库中。这种方式导致了：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Kubernetes 代码库臃肿：&lt;/strong&gt; 集成了大量存储逻辑，增加了核心代码的复杂性和维护难度。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;发布周期长：&lt;/strong&gt; 存储驱动的更新需要跟随 Kubernetes 的发布周期，新功能和 bug 修复不能及时推送到用户。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;存储厂商开发受限：&lt;/strong&gt; 每次更新都需要与 Kubernetes 社区协调，开发和测试流程繁琐。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;兼容性问题：&lt;/strong&gt; 不同存储厂商的存储系统差异巨大，缺乏统一的接口规范，导致存储系统与 Kubernetes 之间的集成困难。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;CSI 的目标就是解决这些问题，实现存储系统与 Kubernetes 的解耦。&lt;/strong&gt; 它定义了一套通用的接口，允许任何存储厂商开发自己的 CSI 驱动，然后通过这些驱动来与 Kubernetes 进行交互，从而为容器提供存储服务。&lt;/p&gt;&#xA;&lt;h3 id=&#34;11-资源定义&#34;&gt;1.1. 资源定义&lt;/h3&gt;&#xA;&lt;h3 id=&#34;111-volumes&#34;&gt;1.1.1. Volumes&lt;/h3&gt;&#xA;&lt;p&gt;Volumes 是 Kubernetes 中 Pod 通过文件系统访问和共享数据的抽象。它主要提供了如下功能：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;通过 ConfigMap 或者 Secret 共享配置；&lt;/li&gt;&#xA;&lt;li&gt;跨容器、跨 Pod 甚至跨 Node 共享数据；&lt;/li&gt;&#xA;&lt;li&gt;数据持久化。在 Pod 销毁之后仍能继续访问数据。&#xA;对于 Pod 来说，Volumes 通过 &lt;code&gt;.spec.volumes&lt;/code&gt; 提供给 Pod，容器通过 &lt;code&gt;.spec.containers[*].volumeMounts&lt;/code&gt; 来将指定 Volumes 挂载到指定目录。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;112-persistent-volumes-和-persistent-volumes-claim&#34;&gt;1.1.2. Persistent Volumes 和 Persistent Volumes Claim&lt;/h3&gt;&#xA;&lt;p&gt;PV 和 PVC 提供了两套 API 将存储的提供和消费分离。&lt;/p&gt;</description>
			</item>
			<item>
				<title>VRF: An Overview</title>
				<link>https://blog.jinzhi.site/posts/2025-04/vrf-an-overview/</link>
				<pubDate>Fri, 25 Apr 2025 20:30:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2025-04/vrf-an-overview/</guid>
				<description>&lt;h2 id=&#34;什么是-vrfvirtual-routing-forwarding&#34;&gt;什么是 VRF（virtual routing forwarding）&lt;/h2&gt;&#xA;&lt;p&gt;VRF是一种实现三层网络隔离的关键技术。&lt;strong&gt;它通过创建多个路由表，为不同的网络流量提供独立的转发路径。&lt;/strong&gt; 这意味着，任何三层网络结构，如接口的IP地址、静态路由的配置，甚至BGP（边界网关协议）会话，都可以被映射到特定的VRF中。这种映射机制就像是为每个VRF构建了一个独立的网络空间，彼此之间相互隔离，极大地增强了网络的安全性和管理的便利性。在MPLS VPN（多协议标签交换虚拟专用网络）等应用场景中，VRF为实现大规模的网络隔离和灵活的路由策略提供了基础框架。就像 VLAN 隔离了二层网络一样，VRF 隔离了三层网络。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/vrf-an-overview/5eb20c3e919fe3724b92c2ae7a66a7da_MD5.png&#34; alt=&#34;5eb20c3e919fe3724b92c2ae7a66a7da_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么需要-vrf&#34;&gt;为什么需要 VRF&lt;/h2&gt;&#xA;&lt;p&gt;在 VRF 出现之前，Linux 用户主要采用两种方式来尝试实现类似的功能：策略路由（policy routing）和网络命名空间（net namespace）。然而，这两种方法都存在明显的局限性。&lt;/p&gt;&#xA;&lt;p&gt;策略路由虽然能够通过多个路由表和策略规则来模拟 VRF 的部分功能（事实上，在 Linux 中，也是基于策略路由来去对 VRF 做的实现），但它的缺点十分突出。这种方式在配置和管理上非常复杂，难以确保网络隔离的有效性，在面对严格的网络审计时，往往无法通过。其复杂性不仅增加了运维的难度，还可能导致网络故障的风险上升，因此不被推荐使用。&lt;/p&gt;&#xA;&lt;p&gt;网络命名空间在容器技术兴起后得到了广泛应用，它能够为容器提供全面的网络隔离。但在模拟 VRF 功能时，却显得有些“大材小用”。网络命名空间会对所有网络相关的资源进行完全隔离，包括设备、接口、ARP 表和路由表等。这意味着，即使是一些不需要隔离的服务，也会被隔离在不同的命名空间中。以 LLDP（链路层发现协议）为例，在使用网络命名空间的情况下，若要在不同的网络隔离环境中使用 LLDP，就需要在每个命名空间中单独运行实例，并且由于默认套接字相同，还需要为每个实例创建独特的套接字。这不仅增加了系统的开销，还使得管理变得更加复杂。相比之下，VRF 在隔离三层网络结构的同时，允许全局配置的共享和非三层感知服务的统一运行，大大提高了资源的利用效率。&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Policy Routing&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;VRF&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Net Namespace&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;隔离路由表&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;隔离三层网络&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;整个协议栈从二层到 socket 隔离&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/vrf-an-overview/a9f7c55f8f39572d339b138fb1e12429_MD5.png&#34; alt=&#34;a9f7c55f8f39572d339b138fb1e12429_MD5&#34;&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/vrf-an-overview/c9b6614c864c7d35a8ef0a4f12ecdbfa_MD5.png&#34; alt=&#34;c9b6614c864c7d35a8ef0a4f12ecdbfa_MD5&#34;&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/vrf-an-overview/9edc8b051f504bf72140d1238513d687_MD5.png&#34; alt=&#34;9edc8b051f504bf72140d1238513d687_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;vrf-配置&#34;&gt;VRF 配置&lt;/h2&gt;&#xA;&lt;p&gt;在 Linux 系统中配置 VRF，主要借助&lt;code&gt;iproute2&lt;/code&gt;包来完成一系列操作。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;创建 VRF，并关联到 table 1&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;test1@test1:~$ ip link add vrf-1 &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; vrf table &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;test1@test1:~$ ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; vrf-1 up&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;添加接口到 VRF，可以看到 wg0 的 master 是 vrf-1，所有 wg0 的流量会使用关联的 vrf-1 路由表进行路由&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;test1@test1:~$ ip link &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; wg0 master vrf-1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;test1@test1:~$ ip -d link show wg0 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;9: wg0: &amp;lt;POINTOPOINT,NOARP,UP,LOWER_UP&amp;gt; mtu &lt;span class=&#34;m&#34;&gt;1400&lt;/span&gt; qdisc noqueue master vrf-1 state UNKNOWN mode DEFAULT group default qlen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    link/none  promiscuity &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; minmtu &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; maxmtu &lt;span class=&#34;m&#34;&gt;2147483552&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    wireguard &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    vrf_slave table &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; addrgenmode none numtxqueues &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; numrxqueues &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; gso_max_size &lt;span class=&#34;m&#34;&gt;65536&lt;/span&gt; gso_max_segs &lt;span class=&#34;m&#34;&gt;65535&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;添加和查看 VRF  静态路由&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@test1:~# ip route add default via 10.1.0.10 vrf vrf-1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@test1:~# ip route show table &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;default via 10.1.0.10 dev wg0 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; 10.1.0.10 dev wg0 proto kernel scope host src 10.1.0.10 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@test1:~# ip route show vrf vrf-1 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;default via 10.1.0.10 dev wg0 &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;vrf-之间路由&#34;&gt;VRF 之间路由&lt;/h3&gt;&#xA;&lt;p&gt;有两种方法可以执行跨 VRF 路由。第一种方法涉及一个 VRF 的表中配置的路由，指向绑定到不同 VRF 的设备。&lt;/p&gt;</description>
			</item>
			<item>
				<title>eBPF 指令集规范</title>
				<link>https://blog.jinzhi.site/posts/2024-01/ebpf-%E6%8C%87%E4%BB%A4%E9%9B%86%E8%A7%84%E8%8C%83/</link>
				<pubDate>Fri, 05 Jan 2024 18:06:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2024-01/ebpf-%E6%8C%87%E4%BB%A4%E9%9B%86%E8%A7%84%E8%8C%83/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://docs.kernel.org/bpf/standardization/instruction-set.html&#34;&gt;1 BPF Instruction Set Specification, v1.0 — The Linux Kernel documentation&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;寄存器和调用约定&#34;&gt;寄存器和调用约定&lt;/h2&gt;&#xA;&lt;p&gt;eBPF有10个通用寄存器和一个只读的帧指针寄存器，所有的寄存器都是64bits位长。&lt;/p&gt;&#xA;&lt;p&gt;eBPF的调用约定如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;R0:&lt;/strong&gt; 函数调用的返回值和eBPF程序的退出值&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;R1 - R5:&lt;/strong&gt; 函数调用的参数&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;R6 - R9:&lt;/strong&gt; callee saved registers，由函数调用负责保存到栈上&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;R10:&lt;/strong&gt; 只读的帧指针，用于访问栈&#xA;R0 - R5是临时寄存器，eBPF程序在函数调用时如需使用需要将它们保存/填充。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;指令编码&#34;&gt;指令编码&lt;/h2&gt;&#xA;&lt;p&gt;eBPF使用64bit指令，编码如下：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;32位（最高有效位）&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;16位&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;4位&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;4位&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;8位（最低有效位）&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;immediate&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;offset&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;source register&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;dest register&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;opcode&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;imm: 有符号整型立即数&lt;/li&gt;&#xA;&lt;li&gt;offset: 有符号整型数，用于指针算术&lt;/li&gt;&#xA;&lt;li&gt;src_reg: 除开特殊指令的编码外（如64位立即数指令）指的是源寄存器(R0 - R10)&lt;/li&gt;&#xA;&lt;li&gt;dst_reg: 目标寄存器(R0 - R10)&lt;/li&gt;&#xA;&lt;li&gt;opcode: 操作码&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;绝大多数指令不会使用所有的字段。没有使用的字段应当被置0。多字节的字段（如imm和offset）在大端BPF中以大端字节序存储，小端BPF中以小端字节序存储。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;opcode                  offset imm          assembly&#xA;       src_reg dst_reg&#xA;07     0       1        00 00  44 33 22 11  r1 += 0x11223344 // little&#xA;       dst_reg src_reg&#xA;07     1       0        00 00  11 22 33 44  r1 += 0x11223344 // big&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;除了这些基本指令编码外，eBPF还有一种宽指令编码，在基本指令之后使用第2个64位立即数做扩展。第2个立即数包括一个伪指令，和基本指令的格式一样，不过所有的字段（除了imm）都置为0。它的imm作为整个宽指令中的imm64值的高32位：&lt;/p&gt;</description>
			</item>
			<item>
				<title>eBPF 全局变量的实现</title>
				<link>https://blog.jinzhi.site/posts/2024-01/ebpf-%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E7%9A%84%E5%AE%9E%E7%8E%B0/</link>
				<pubDate>Tue, 02 Jan 2024 19:46:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2024-01/ebpf-%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E7%9A%84%E5%AE%9E%E7%8E%B0/</guid>
				<description>&lt;p&gt;Linux内核在v5.2支持了eBPF全局变量（见&lt;a href=&#34;https://www.yuque.com/chengzhycn/hx665b/cmbgkdheaf0wyqht#vVcxE&#34;&gt;v5.2&lt;/a&gt;）。&lt;/p&gt;&#xA;&lt;p&gt;全局变量会被Clang编译器放入&lt;code&gt;.bss&lt;/code&gt;, &lt;code&gt;.data&lt;/code&gt;, &lt;code&gt;.rodata&lt;/code&gt; sections。那么支持全局变量即如何把这些sections中的数据加载进内核，并且在relocation时，给访问这些变量的指令正确的地址。&lt;/p&gt;&#xA;&lt;h2 id=&#34;早期-workaround&#34;&gt;早期 workaround&lt;/h2&gt;&#xA;&lt;p&gt;关于 eBPF 静态变量支持的讨论在&lt;a href=&#34;https://lpc.events/event/2/contributions/115/&#34;&gt;Linux Plumbers Conference 2018&lt;/a&gt; 由Cilium提出。早期的 workaround 如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;linux/bpf.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifndef __section&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;# define __section(NAME)&#x9;&#x9;&#x9;&#x9;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&#x9;__attribute__((section(NAME), used))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifndef __fetch&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;# define __fetch(x) (__u32)(__u64)(&amp;amp;(x))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;42&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &#x9;&#x9;&#x9;&lt;span class=&#34;c1&#34;&gt;// .data section&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// __u32 foo;   &#x9;&#x9;&#x9;// .bss section&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// const __u32 foo = 42; &#x9;// .rodata section&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__sk_buff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;skb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;skb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mark&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__fetch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__license&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;license&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译后，foo变量存储在&lt;code&gt;.data&lt;/code&gt; section内。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# llvm-readelf -S test.o&#xA;There are 8 section headers, starting at offset 0x148:&#xA;&#xA;Section Headers:&#xA;  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al&#xA;  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0&#xA;  [ 1] .strtab           STRTAB          0000000000000000 0000fa 00004b 00      0   0  1&#xA;  [ 2] .text             PROGBITS        0000000000000000 000040 000028 00  AX  0   0  8&#xA;  [ 3] .rel.text         REL             0000000000000000 0000e8 000010 10      7   2  8&#xA;  [ 4] .data             PROGBITS        0000000000000000 000068 000004 00  WA  0   0  4&#xA;  [ 5] license           PROGBITS        0000000000000000 00006c 000001 00  WA  0   0  1&#xA;  [ 6] .llvm_addrsig     LLVM_ADDRSIG    0000000000000000 0000f8 000002 00   E  7   0  1&#xA;  [ 7] .symtab           SYMTAB          0000000000000000 000070 000078 18      1   2  8&#xA;Key to Flags:&#xA;  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),&#xA;  L (link order), O (extra OS processing required), G (group), T (TLS),&#xA;  C (compressed), x (unknown), o (OS specific), E (exclude),&#xA;  p (processor specific)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;.rel.text&lt;/code&gt; section中也存在foo变量的relocation信息：&lt;/p&gt;</description>
			</item>
			<item>
				<title>Linux 收包和发包流程</title>
				<link>https://blog.jinzhi.site/posts/2022-10/linux-%E6%94%B6%E5%8C%85%E5%92%8C%E5%8F%91%E5%8C%85%E6%B5%81%E7%A8%8B/</link>
				<pubDate>Thu, 13 Oct 2022 14:30:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2022-10/linux-%E6%94%B6%E5%8C%85%E5%92%8C%E5%8F%91%E5%8C%85%E6%B5%81%E7%A8%8B/</guid>
				<description>&lt;h2 id=&#34;流程图&#34;&gt;流程图&lt;/h2&gt;&#xA;&lt;p&gt;From 《Understanding Linux Network Internals》&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/linux-%E6%94%B6%E5%8C%85%E5%92%8C%E5%8F%91%E5%8C%85%E6%B5%81%E7%A8%8B/image-20220128172744059.png&#34; alt=&#34;image-20220128172744059&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/linux-%E6%94%B6%E5%8C%85%E5%92%8C%E5%8F%91%E5%8C%85%E6%B5%81%E7%A8%8B/image-20220129171450456.png&#34; alt=&#34;image-20220129171450456&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;收包流程&#34;&gt;收包流程&lt;/h2&gt;&#xA;&lt;p&gt;TL; DR&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/linux-%E6%94%B6%E5%8C%85%E5%92%8C%E5%8F%91%E5%8C%85%E6%B5%81%E7%A8%8B/Linux_Packet_Receive_Flow.png&#34; alt=&#34;image-20220129171450456&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;收包&lt;code&gt;NET_RX_SOFTRQ&lt;/code&gt;的软中断处理函数是&lt;code&gt;net_rx_action&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;net_rx_action&lt;/code&gt;中会调用网卡驱动注册的poll回调函数处理&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;poll回调函数将数据帧从网卡ring buffer中取出，构造skb：&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;运行xdpdrv上的bpf program，得到action result&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;如果是XDP_PASS，构造skb，并初始化skb中一些metadata字段&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;调用内核的GRO和RPS处理流程&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;进入&lt;code&gt;__netif_receive_skb_core&lt;/code&gt;，处理skb：&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;运行xdpgeneric上的bpf program，得到action result&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;如果是XDP_PASS，遍历&lt;code&gt;ptype_all&lt;/code&gt;和&lt;code&gt;dev-&amp;gt;ptype_all&lt;/code&gt;，进行抓包处理&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;tc ingress 处理&lt;code&gt;sch_handle_ingress&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;查找&lt;code&gt;ptype_base&lt;/code&gt;和&lt;code&gt;dev-&amp;gt;ptype_specific&lt;/code&gt;，交由对应的三层协议栈回调函数处理&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;napi&#34;&gt;NAPI&lt;/h3&gt;&#xA;&lt;p&gt;**NAPI的思想是从完全的中断收包模型，改用中断和polling混合。**如果内核在处理旧的数据帧时，收到了新的数据帧，网卡设备没有必要再触发一个中断。内核继续处理设备input queue里的数据（该设备的interrupt禁止了），在队列为空时重新使能中断。&lt;/p&gt;&#xA;&lt;p&gt;从内核的角度，NAPI有如下的优势：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;降低CPU的负载（更少的中断）&lt;/li&gt;&#xA;&lt;li&gt;更多的设备处理公平性&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;以ixgbe网卡为例，描述下NAPI处理流程。&lt;/p&gt;&#xA;&lt;h4 id=&#34;注册&#34;&gt;注册&lt;/h4&gt;&#xA;&lt;p&gt;ixgbe驱动在初始化中断向量时会调用&lt;code&gt;netif_napi_add&lt;/code&gt;初始化NAPI，==&lt;strong&gt;将&lt;code&gt;ixgbe_poll&lt;/code&gt;函数注册到napi结构体，并将napi加入到设备的napi_list内&lt;/strong&gt;==：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * ixgbe_alloc_q_vector - Allocate memory for a single interrupt vector&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @adapter: board private structure to initialize&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @v_count: q_vectors allocated on adapter, used for ring interleaving&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @v_idx: index of vector in adapter struct&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @txr_count: total number of Tx rings to allocate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @txr_idx: index of first Tx ring to allocate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @xdp_count: total number of XDP rings to allocate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @xdp_idx: index of first XDP ring to allocate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @rxr_count: total number of Rx rings to allocate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @rxr_idx: index of first Rx ring to allocate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * We allocate one q_vector.  If allocation fails we return -ENOMEM.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; **/&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ixgbe_alloc_q_vector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ixgbe_adapter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;adapter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;v_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;v_idx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;txr_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;txr_idx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;xdp_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;xdp_idx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rxr_count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rxr_idx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* initialize NAPI */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;netif_napi_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;adapter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;netdev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;q_vector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;napi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               &lt;span class=&#34;n&#34;&gt;ixgbe_poll&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;中断处理函数&#34;&gt;中断处理函数&lt;/h4&gt;&#xA;&lt;p&gt;ixgbe驱动收到中断后，会调用&lt;code&gt;ixgbe_msix_clean_rings&lt;/code&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>make命令和编译</title>
				<link>https://blog.jinzhi.site/posts/2022-07/make%E5%91%BD%E4%BB%A4%E5%92%8C%E7%BC%96%E8%AF%91/</link>
				<pubDate>Tue, 26 Jul 2022 14:30:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2022-07/make%E5%91%BD%E4%BB%A4%E5%92%8C%E7%BC%96%E8%AF%91/</guid>
				<description>&lt;h2 id=&#34;makefile&#34;&gt;Makefile&lt;/h2&gt;&#xA;&lt;h3 id=&#34;标准格式&#34;&gt;标准格式&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;target：dependencies1 dependencies2 ...&#xA;   recipe&#xA;&#xA;.PHONY: clean&#xA;clean:&#xA;   -rm ...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;注意事项&#34;&gt;注意事项&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;运行make时如果没有指定target，那么make会构建Makefile中的第一个target&lt;/li&gt;&#xA;&lt;li&gt;通常情况下，目标名即生成的文件名。如果一条规则的目标文件存在并且该文件比它所有的依赖都要新，那么make会跳过recipe；如果目标文件不存在，那么目标文件的 &lt;strong&gt;timestamp&lt;/strong&gt; 为开始的时间；否则timestamp为相应文件的修改时间。&lt;/li&gt;&#xA;&lt;li&gt;每次运行 &lt;code&gt;make clean&lt;/code&gt;，”clean“中的recipe都会被执行，因为clean文件永远都不会被创建。（可以使用 &lt;strong&gt;.PHONY&lt;/strong&gt; 创建伪目标使Makefile可读性更高）&lt;/li&gt;&#xA;&lt;li&gt;recipes必须用tab缩进&lt;/li&gt;&#xA;&lt;li&gt;可以通过并行的方式运行recipes：&lt;code&gt;make -j 4&lt;/code&gt;（指定并行的任务数）&lt;/li&gt;&#xA;&lt;li&gt;如果没有指定规则，Make会自动化创建规则。例如，本地有一个C文件”program.c“，当运行 &lt;code&gt;make program&lt;/code&gt;时，Make会自动编译生成 program&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;变量&#34;&gt;变量&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;$@&lt;/code&gt; 目标文件&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;$^&lt;/code&gt; 所有的依赖文件&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;$&amp;lt;&lt;/code&gt; 第一个依赖&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;头文件&#34;&gt;头文件&lt;/h2&gt;&#xA;&lt;h3 id=&#34;环境变量&#34;&gt;环境变量&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;C_INCLUDE_PATH&lt;/code&gt; C语言头文件路径&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;CPLUS_INCLUDE_PATH&lt;/code&gt; C++ 头文件路径&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;搜索路径&#34;&gt;搜索路径&lt;/h3&gt;&#xA;&lt;h4 id=&#34;include&#34;&gt;#include&amp;lt;&amp;gt;&lt;/h4&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;先搜索 &lt;code&gt;-I&lt;/code&gt; 指定的目录&lt;/li&gt;&#xA;&lt;li&gt;然后搜索gcc的环境变量 &lt;code&gt;CPLUS_INCLUDE_PATH&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;最后搜索gcc的内定目录&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;code&gt;/usr/include&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;/usr/local/include&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;/usr/lib/gcc/x86_64-redhat-linux/4.1.1/include&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h4 id=&#34;include-&#34;&gt;#include &amp;quot;&amp;quot;&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;搜索当前目录，#include&amp;lt;&amp;gt;方式不会搜索当前目录&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;动态库&#34;&gt;动态库&lt;/h2&gt;&#xA;&lt;h3 id=&#34;环境变量-1&#34;&gt;环境变量&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt;  动态链接库搜索路径&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;PKG_CONFIG_PATH&lt;/code&gt; .pc文件（package config）文件搜索路径&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;搜索路径-1&#34;&gt;搜索路径&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;首先在环境变量 &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; 所记录的路径中查找&lt;/li&gt;&#xA;&lt;li&gt;在程序链接时指定的 rpath 中查找，可以  &lt;code&gt;readelf binfile | grep RPATH&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;然后从缓存文件/etc/ld.so.cache中查找。这个缓存文件由/sbin/ldconfig命令读取配置文件/etc/ld.so.conf 之后生成（也可以在 ld.so.conf.d 目录下增加 &lt;em&gt;.conf 文件，里面写入库路径，在 ld.so.conf 中 include ld.so.conf.d/&lt;/em&gt;.conf ）&lt;/li&gt;&#xA;&lt;li&gt;如果上述步骤都找不到，则到默认的系统路径中查找，先是/usr/lib然后是/lib&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/masterpanda/p/5700446.html&#34;&gt;https://www.cnblogs.com/masterpanda/p/5700446.html&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;编译参数&#34;&gt;编译参数&lt;/h3&gt;&#xA;&lt;h4 id=&#34;-shared&#34;&gt;-shared&lt;/h4&gt;&#xA;&lt;p&gt;指定生成动态连接库&lt;/p&gt;</description>
			</item>
			<item>
				<title>ELF 文件格式浅析</title>
				<link>https://blog.jinzhi.site/posts/2022-05/elf-%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E6%B5%85%E6%9E%90/</link>
				<pubDate>Fri, 27 May 2022 09:30:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2022-05/elf-%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E6%B5%85%E6%9E%90/</guid>
				<description>&lt;p&gt;本文是作为 Rust 的练手项目 rself(&lt;a href=&#34;https://github.com/chengzhycn/rself&#34;&gt;https://github.com/chengzhycn/rself&lt;/a&gt;) 的背景知识记录。rself 使用 Rust 重新造了一个 readelf 的轮子。&lt;/p&gt;&#xA;&lt;p&gt;ELF全称为&lt;strong&gt;Executable and Linkable Format&lt;/strong&gt;，是Linux上可执行文件的通用文件格式。主要有三种类型的ELF文件：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Relocatable file&lt;/strong&gt;: 存储用于和其它对象文件链接的代码和数据，创建一个可执行文件或者共享对象文件&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Executable file&lt;/strong&gt;: 存储的是用于执行的程序。它指定了exec如何创建一个程序的进程镜像&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Shared object file&lt;/strong&gt;: 存储了在两种语义下用于链接的代码和数据。第一种是让链接器将共享对象文件和其它的可重定位文件/共享对象文件一起创建一个新的对象文件；第二种是动态链接器将它和可执行文件以及其它的共享对象一起创建一个进程镜像。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;elf构成&#34;&gt;ELF构成&lt;/h2&gt;&#xA;&lt;p&gt;ELF主要由如下几个部分组成：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;ELF Header&lt;/strong&gt;: 位于文件的起始，描述了整个文件的组织结构&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Sections/Segments&lt;/strong&gt;: 存储了指令、数据、符号表、可重定位信息等。sections 是这段数据在链接时的表现；segments 是数据在执行时的表现。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Program Header Table&lt;/strong&gt;: 用于告诉系统如何创建一个进程镜像。对于可执行程序，Program Header Table是必须的，但是对于可重定位文件就不需要了。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Section Header Table&lt;/strong&gt;: 存储描述文件中sections的信息。每个section都在这个表中有一个条目，存储了如section name, section size等信息。用于链接的文件必须得有Section Header Table，其它的对象文件可有可无。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/elf-%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E6%B5%85%E6%9E%90/d02c13c1fa4bd228f698cf355ec47377_MD5.png&#34; alt=&#34;d02c13c1fa4bd228f698cf355ec47377_MD5&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;上面的图中虽然描述文件各个部分的位置，但实际上只有ELF Header的位置是固定的，其它的部分在文件中的位置都在ELF Header中指定。&lt;/p&gt;&#xA;&lt;h2 id=&#34;elf-header&#34;&gt;ELF Header&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#define EI_NIDENT 16&#xA;&#xA;typedef struct {&#xA;        unsigned char   e_ident[EI_NIDENT];&#xA;        Elf32_Half      e_type;&#xA;        Elf32_Half      e_machine;&#xA;        Elf32_Word      e_version;&#xA;        Elf32_Addr      e_entry;&#xA;        Elf32_Off       e_phoff;&#xA;        Elf32_Off       e_shoff;&#xA;        Elf32_Word      e_flags;&#xA;        Elf32_Half      e_ehsize;&#xA;        Elf32_Half      e_phentsize;&#xA;        Elf32_Half      e_phnum;&#xA;        Elf32_Half      e_shentsize;&#xA;        Elf32_Half      e_shnum;&#xA;        Elf32_Half      e_shstrndx;&#xA;} Elf32_Ehdr;&#xA;&#xA;typedef struct {&#xA;        unsigned char   e_ident[EI_NIDENT];&#xA;        Elf64_Half      e_type;&#xA;        Elf64_Half      e_machine;&#xA;        Elf64_Word      e_version;&#xA;        Elf64_Addr      e_entry;&#xA;        Elf64_Off       e_phoff;&#xA;        Elf64_Off       e_shoff;&#xA;        Elf64_Word      e_flags;&#xA;        Elf64_Half      e_ehsize;&#xA;        Elf64_Half      e_phentsize;&#xA;        Elf64_Half      e_phnum;&#xA;        Elf64_Half      e_shentsize;&#xA;        Elf64_Half      e_shnum;&#xA;        Elf64_Half      e_shstrndx;&#xA;} Elf64_Ehdr;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ELF header通常由一个Elfxx_Ehdr结构体表示。它存储了当前二进制文件的一些元数据：&lt;/p&gt;</description>
			</item>
			<item>
				<title>Linux 进程调度</title>
				<link>https://blog.jinzhi.site/posts/2022-01/linux-%E8%BF%9B%E7%A8%8B%E8%B0%83%E5%BA%A6/</link>
				<pubDate>Tue, 11 Jan 2022 14:30:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2022-01/linux-%E8%BF%9B%E7%A8%8B%E8%B0%83%E5%BA%A6/</guid>
				<description>&lt;p&gt;总体来说，调度主要解决两类问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;什么时候调度&lt;/li&gt;&#xA;&lt;li&gt;调度的目标是谁&#xA;而一个优秀的调度系统，可以从如下几个指标判断：&lt;/li&gt;&#xA;&lt;li&gt;fast process response time&lt;/li&gt;&#xA;&lt;li&gt;good throughput for background jobs&lt;/li&gt;&#xA;&lt;li&gt;avoidance of process starvation&lt;/li&gt;&#xA;&lt;li&gt;reconciliation of the needs of low- and high- priority processes&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Linux调度基于分时（Time-Sharing）：多个进程共享同一个CPU，CPU运行时切分成多个时间片。分时技术依赖于timer interrupt，对进程来说是透明的。&lt;/p&gt;&#xA;&lt;p&gt;Linux进程是&lt;strong&gt;可抢占&lt;/strong&gt;的。当进程切换到&lt;code&gt;TASK_RUNNING&lt;/code&gt;状态，内核检查其动态优先级是否比当前运行的进程的优先级高。如果更高，当前执行的进程中断掉，调度器切入，选择另外一个进程运行（通常是刚刚切换成runnable的进程）。当进程的时间片消耗完毕时，进程也是可被抢占的。当前进程&lt;code&gt;struct thread_info&lt;/code&gt;中的&lt;code&gt;TIF_NEED_RESCHED&lt;/code&gt;被设置，timer interrupt handler终止后，scheduler切入。&lt;/p&gt;&#xA;&lt;p&gt;一个被抢占的进程并不是被暂停，它还维持在&lt;code&gt;TASK_RUNNING&lt;/code&gt;状态，只不过不再使用CPU。&lt;/p&gt;&#xA;&lt;h2 id=&#34;调度算法&#34;&gt;调度算法&lt;/h2&gt;&#xA;&lt;p&gt;Linux 2.6版本之前的调度算法很简单，进程切换时，内核扫描runnable进程列表，计算它们的优先级，选择“最优”的进程运行。这种算法的问题是切换时的时间开销会随着进程数目的增多呈线性增长。&lt;/p&gt;&#xA;&lt;p&gt;调度策略：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;SCHED_FIFO&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;SCHED_RR&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;SCHED_NORMAL&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;o1-scheduler&#34;&gt;O(1) Scheduler&lt;/h3&gt;&#xA;&lt;p&gt;基于Linux-2.6.12版本。&lt;/p&gt;&#xA;&lt;h4 id=&#34;优先级&#34;&gt;优先级&lt;/h4&gt;&#xA;&lt;p&gt;Linux 2.6.12 内核里，优先级表示分为用户态和内核态。用户态优先级就是我们常用的nice值。取值范围[-20, 19]。内核态优先级被称作静态优先级（static priority），取值范围是[0, 139]。其中，[0, 99]是Real-Time Process，[100, 139]对应用户态nice值。&lt;/p&gt;&#xA;&lt;p&gt;在静态优先级外，真正发挥作用的是&lt;strong&gt;动态优先级（dynamic priority）&lt;/strong&gt;。动态优先级实际上是静态优先级加上了一个运行时补偿（bonus）：&#xA;$$&#xA;dynamic_priority = max(100, min((static_priority - 5 + bonus), 139)), bonus \in [0, 10]&#xA;$$&lt;/p&gt;</description>
			</item>
			<item>
				<title>Linux 进程</title>
				<link>https://blog.jinzhi.site/posts/2021-11/linux-%E8%BF%9B%E7%A8%8B/</link>
				<pubDate>Tue, 30 Nov 2021 08:30:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2021-11/linux-%E8%BF%9B%E7%A8%8B/</guid>
				<description>&lt;h2 id=&#34;进程和轻量级进程&#34;&gt;进程和轻量级进程&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/linux-%E8%BF%9B%E7%A8%8B/image-20211112165309944.png&#34; alt=&#34;image-20211112165309944&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在Linux内核中，进程/线程对应的数据结构是&lt;code&gt;task_struct&lt;/code&gt;，定义在&lt;code&gt;include/linux/sched.h&lt;/code&gt;中。&lt;/p&gt;&#xA;&lt;p&gt;线程在Linux中的实现是 &lt;strong&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Native_POSIX_Thread_Library&#34;&gt;Naive POSIX Thread Library&lt;/a&gt;&lt;/strong&gt; 。在内核眼中，Linux的线程实际上也是一个进程（&lt;code&gt;task_struct&lt;/code&gt;），区别是线程的“进程”共享了地址空间、文件描述符等，称作==&lt;strong&gt;轻量级进程&lt;/strong&gt;==。因此，Linux的线程也是独立的调度单元，是可以分别在不同的CPU上同时运行的。原生的Linux 线程（2.6版本内核之前）因为只实现在了用户态，所以，即使是一个多线程程序，对于内核来说只能看到一个进程，这些线程就只能在一个CPU上运行，对于多核多线程来说是很致命的。&lt;/p&gt;&#xA;&lt;p&gt;从实现的角度，Linux的线程（LWP）是通过pthread库创建/使用的。而进程和线程的创建都调用了&lt;code&gt;clone()&lt;/code&gt;系统调用（&lt;code&gt;kernel/fork.c&lt;/code&gt; ）。区别是两者使用了不同的flags。&lt;/p&gt;&#xA;&lt;h2 id=&#34;进程管理&#34;&gt;进程管理&lt;/h2&gt;&#xA;&lt;h3 id=&#34;进程状态&#34;&gt;进程状态&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;TASK_RUNNING&lt;/strong&gt;: The process is either executing on a CPU or waiting to be executed&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;TASK_INTERRUPTIBLE&lt;/strong&gt;: The process is suspended (sleeping) until some condition becomes true.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;TASK_UNINTERRUPTIBLE&lt;/strong&gt;: Like TASK_INTERRUPTIBLE, except that delivering a signal to the sleeping process leaves its state unchanged.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;pid&#34;&gt;PID&lt;/h3&gt;&#xA;&lt;p&gt;PID用来区分不同的进程结构体。Linux中最大PID数目可以在&lt;code&gt;/proc/sys/kernel/pid_max&lt;/code&gt;中查看。&lt;/p&gt;&#xA;&lt;p&gt;每个进程/轻量级进程都分配有一个唯一的PID。但是对于同一进程中的线程来说，我们拿到的是进程ID确是相同的，这是怎么实现的呢？&lt;/p&gt;&#xA;&lt;p&gt;Linux为了兼容POSIX标准，利用了线程组（thread group）这一概念。所有的线程都会把线程组里面第一个线程的PID存在tgid字段内。==getpid()系统调用返回的实际上是tgid的值。==&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * sys_getpid - return the thread group id of the current process&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Note, despite the name, this returns the tgid not the pid.  The tgid and&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * the pid are identical unless CLONE_THREAD was specified on clone() in&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * which case the tgid is the same in all threads of the same group.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * This is SMP safe as current-&amp;gt;tgid does not change.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;SYSCALL_DEFINE0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;task_tgid_vnr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;bitmap管理pid&#34;&gt;bitmap管理PID&lt;/h4&gt;&#xA;&lt;h4 id=&#34;idr管理pid&#34;&gt;IDR管理PID&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;PID: replace pid bitmap implementation with IDR API &lt;a href=&#34;https://git.kernel.org/linus/95846ecf9dac5089aed4b144d912225f8ef86ae4&#34;&gt;commit&lt;/a&gt;, &lt;a href=&#34;https://git.kernel.org/linus/e8cfbc245e24887e3c30235f71e9e9405e0cfc39&#34;&gt;commit&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;进程切换&#34;&gt;进程切换&lt;/h2&gt;&#xA;&lt;p&gt;==&lt;strong&gt;TLDR&lt;/strong&gt;：进程在调用&lt;code&gt;schedule()&lt;/code&gt;方法时，将当前进程运行的寄存器信息保存在&lt;code&gt;task_struct-&amp;gt;thread_info&lt;/code&gt;内，同时从进程B中的&lt;code&gt;task_struct-&amp;gt;thread_info&lt;/code&gt;中加载B运行时的寄存器信息。==&lt;/p&gt;</description>
			</item>
			<item>
				<title>Go channel 实现</title>
				<link>https://blog.jinzhi.site/posts/2021-09/go-channel-%E5%AE%9E%E7%8E%B0/</link>
				<pubDate>Sun, 12 Sep 2021 09:30:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2021-09/go-channel-%E5%AE%9E%E7%8E%B0/</guid>
				<description>&lt;p&gt;Go的Channel在runtime里面是一个hchan的结构体，每次我们make一个新的channel时，runtime从heap内分配一个hchan结构体管理channel。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hchan&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;qcount&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// total data in the queue&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dataqsiz&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// size of the circular queue&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Pointer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// points to an array of dataqsiz elements&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;elemsize&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint16&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;closed&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint32&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;elemtype&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;_type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// element type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sendx&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// send index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;recvx&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// receive index&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;recvq&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;waitq&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// list of recv waiters&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sendq&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;waitq&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// list of send waiters&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// lock protects all fields in hchan, as well as several&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// fields in sudogs blocked on this channel.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;    // Do not change another G&amp;#39;s status while holding this lock&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// (in particular, do not ready a G), as this can deadlock&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// with stack shrinking.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mutex&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;qcount：当前channel queue内的element数目，当qcount等于dataqsiz时，表示channel buffer已经满了，send channel会被阻塞；&lt;/li&gt;&#xA;&lt;li&gt;dataqsiz：channel的buffer大小，也就是我们在make时设定的值。dataqsiz在channel创建后不会再变动，因此channel的buffer是不会动态扩容的；&lt;/li&gt;&#xA;&lt;li&gt;buf：buffered channel缓存elements的内存地址。是一个数组实现的环形队列；&lt;/li&gt;&#xA;&lt;li&gt;elemsize：element类型大小；&lt;/li&gt;&#xA;&lt;li&gt;closed：channel是否已经被关闭，防止关闭已经关闭的channel；&lt;/li&gt;&#xA;&lt;li&gt;elemtype：channel element 类型；&lt;/li&gt;&#xA;&lt;li&gt;sendx：buffer中下一个生产的element的index；&lt;/li&gt;&#xA;&lt;li&gt;recvx：buffer中下一个消费的element的index；&lt;/li&gt;&#xA;&lt;li&gt;recvq：阻塞的接收channel，是一个sudog的链表&lt;/li&gt;&#xA;&lt;li&gt;sendq：阻塞的发送channel，是一个sudog的链表&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;当buffer没有满时，send channel发送elements时直接把elements放在buf内，增加sendx和qcount；当buffer满时，send channel被阻塞，并加入到sendq链表内，等待被唤醒；&lt;/p&gt;</description>
			</item>
			<item>
				<title>Rust: Concurrency</title>
				<link>https://blog.jinzhi.site/posts/2021-06/rust-concurrency/</link>
				<pubDate>Sun, 27 Jun 2021 09:30:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2021-06/rust-concurrency/</guid>
				<description>&lt;h2 id=&#34;为什么rust不做green-threading&#34;&gt;为什么Rust不做green threading&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/rust-lang/rfcs/blob/master/text/0230-remove-runtime.md&#34;&gt;remove-runtime rfcs&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/rust-lang/rfcs/pull/230&#34;&gt;remove-runtime pull request&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;send-和-sync&#34;&gt;Send 和 Sync&lt;/h2&gt;&#xA;&lt;p&gt;Rust中几乎所有的并发特性都是标准库或者第三方库提供的，真正由Rust语言本身提供的很少。而&lt;code&gt;std::marker&lt;/code&gt;中的traits &lt;code&gt;Send&lt;/code&gt;和&lt;code&gt;Sync&lt;/code&gt;算是其中一个。&lt;/p&gt;&#xA;&lt;p&gt;**实现&lt;code&gt;Send&lt;/code&gt;的类型值的所有权可以在线程间传递。**Rust中绝大多数类型都实现了&lt;code&gt;Send&lt;/code&gt;，但也有些例外，如&lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt;：因为如果将&lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt;的拷贝值的所有权在多个线程中传递，Rust无法保证&lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt;引用值的正确性。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;实现&lt;code&gt;Sync&lt;/code&gt;的类型表示该类型值可以在多个线程中被引用。也就是说，如果&lt;code&gt;&amp;amp;T&lt;/code&gt;实现了&lt;code&gt;Send&lt;/code&gt;，那么类型&lt;code&gt;T&lt;/code&gt;就是&lt;code&gt;Sync&lt;/code&gt;。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;Send&lt;/code&gt;和&lt;code&gt;Sync&lt;/code&gt; markers其实就是将其他语言中的一些潜规则显式地标明出来，让编译器提前检查出代码中的隐患。&lt;/p&gt;&#xA;&lt;h2 id=&#34;线程原语&#34;&gt;线程原语&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;use&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;thread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;vec!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;thread&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;spawn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Here&amp;#39;s a vector: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{:?}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unwrap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;thread::spawn&lt;/code&gt;新建一个线程，执行传递的闭包函数，返回一个&lt;code&gt;JoinHandler&lt;/code&gt;，可以在主线程中调用&lt;code&gt;join&lt;/code&gt;等待子线程结束。&lt;code&gt;move&lt;/code&gt;用于强制闭包获取它使用的变量的所有权。&lt;/p&gt;&#xA;&lt;p&gt;我们可以看看&lt;code&gt;thread::spawn&lt;/code&gt;的实现：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#[stable(feature = &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;rust1&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;, since = &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;)]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;pub&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;spawn&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;F&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;F&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-&amp;gt; &lt;span class=&#34;nc&#34;&gt;JoinHandle&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;where&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;F&lt;/span&gt;: &lt;span class=&#34;nb&#34;&gt;FnOnce&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-&amp;gt; &lt;span class=&#34;nc&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;F&lt;/span&gt;: &lt;span class=&#34;nb&#34;&gt;Send&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;&amp;#39;static&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;T&lt;/span&gt;: &lt;span class=&#34;nb&#34;&gt;Send&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;&amp;#39;static&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Builder&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;spawn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;expect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;failed to spawn thread&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;spawn&lt;/code&gt;的入参和返回值都实现&lt;code&gt;Send&lt;/code&gt;，同时其生命周期为&lt;code&gt;&#39;static&lt;/code&gt;。这是因为在多线程中，每个线程的执行周期不是同步的。父线程或者子线程的结束都会导致入参或者返回值的生命周期不满足Rust的约束条件。&lt;/p&gt;</description>
			</item>
			<item>
				<title>Rust：Generic and Traits</title>
				<link>https://blog.jinzhi.site/posts/2021-06/rustgeneric-and-traits/</link>
				<pubDate>Fri, 25 Jun 2021 14:30:28 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2021-06/rustgeneric-and-traits/</guid>
				<description>&lt;h2 id=&#34;泛型&#34;&gt;泛型&lt;/h2&gt;&#xA;&lt;p&gt;Rust 泛型会在编译时根据参数将泛型单态化（&lt;em&gt;Monomorphization&lt;/em&gt; ），因此，Rust 泛型在运行时是没有任何损耗的。&lt;/p&gt;&#xA;&lt;h3 id=&#34;泛型在函数定义&#34;&gt;泛型在函数定义&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;largest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;T&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;std&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;cmp&lt;/span&gt;::&lt;span class=&#34;nb&#34;&gt;PartialOrd&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;Copy&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;list&lt;/span&gt;: &lt;span class=&#34;kp&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;-&amp;gt; &lt;span class=&#34;nc&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;mut&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;largest&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;item&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;item&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;largest&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;largest&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;item&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;largest&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;number_list&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;vec!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;34&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;50&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;43&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;the largest number is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;largest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;number_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;char_list&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;vec!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;sc&#34;&gt;&amp;#39;y&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;sc&#34;&gt;&amp;#39;m&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;sc&#34;&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;sc&#34;&gt;&amp;#39;d&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;the largest char is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;largest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;char_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;泛型在结构体定义&#34;&gt;泛型在结构体定义&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Point&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;: &lt;span class=&#34;nc&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Point&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;: &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;x is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;, y is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Point&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;: &lt;span class=&#34;mf&#34;&gt;5.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;: &lt;span class=&#34;mf&#34;&gt;3.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;x is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;, y is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要注意，这里表示结构体内x和y是同一种类型，如果需要x和y类型不同，需要定义两个泛型参数。&lt;/p&gt;</description>
			</item>
			<item>
				<title>Rust：Ownership</title>
				<link>https://blog.jinzhi.site/posts/2021-06/rustownership/</link>
				<pubDate>Wed, 23 Jun 2021 22:24:24 +0800</pubDate>
				<guid>https://blog.jinzhi.site/posts/2021-06/rustownership/</guid>
				<description>&lt;p&gt;所有权（Ownership）是Rust中最独特的特性之一。正是因为所有权，Rust才能够在不需要GC的情况下保证内存安全。&lt;/p&gt;&#xA;&lt;p&gt;我们常用的语言中，内存管理一般分为两种：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;自管理，谁分配的谁负责回收，如果没有回收，就会导致内存泄漏。如C、C++。&lt;/li&gt;&#xA;&lt;li&gt;由统一的垃圾回收器管理，GC负责追踪和管理已分配内存，如果内存不再被使用，则由GC进行回收。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Rust选择了第三种，内存会在拥有它的变量离开作用域时回收。因此，理解Rust的内存管理，就需要理解Rust中的所有权、借用规则、生命周期等概念。Rust会在编译过程中校验变量是否符合借用规则，从而保证运行时的内存安全，而且没有GC的额外开销。&lt;/p&gt;&#xA;&lt;p&gt;在C++中，这种模式也被称作&lt;strong&gt;Resource Acquisition Is Initialization (RAII)&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;所有权基本规则&#34;&gt;所有权基本规则&lt;/h3&gt;&#xA;&lt;p&gt;所有权有三条基本规则：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Rust中每个值都有一个对应的变量称之为所有者（owner）；&lt;/li&gt;&#xA;&lt;li&gt;同一时刻，一个值只能存在一个所有者；&lt;/li&gt;&#xA;&lt;li&gt;当所有者离开作用域时，其拥有的值会被丢弃。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;copy和move&#34;&gt;copy和move&lt;/h3&gt;&#xA;&lt;p&gt;因为同一时刻，一个值只能存在一个所有者，对于所有权的转让，Rust根据对象类型分为两种。&lt;/p&gt;&#xA;&lt;p&gt;一种是Copy。即将值做拷贝，拷贝后，原变量拥有原值的所有权，新变量拥有新值的所有权，没有所有权的转移，两者可以同时使用。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;x is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;, y is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// valid&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;支持Copy操作常见的类型通常是只存储在栈上的数据类型，如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;所有的integer类型，如u32；&lt;/li&gt;&#xA;&lt;li&gt;bool值；&lt;/li&gt;&#xA;&lt;li&gt;char值；&lt;/li&gt;&#xA;&lt;li&gt;所有的float类型，如f64；&lt;/li&gt;&#xA;&lt;li&gt;元组，如果其包含的类型也都是支持Copy的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这些类型都实现了Copy特型。如果一种类型实现了Copy特型，在分配新变量后，原变量仍是可用的。&lt;/p&gt;&#xA;&lt;p&gt;另外一种是Move。对于类似String这种在栈上存储了元数据，实际数据存储在堆上的数据类型来说，将原变量赋给新变量实际上是将堆上数据的所有权转移给新变量，原变量在赋值后不再使用。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;String&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hello!!!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;fm&#34;&gt;println!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;s2 is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;, s1 is &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// invalid, s1 is no longer valid any more.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://blog.jinzhi.site/images/notes/rustownership/image-20210623093004432.png&#34; alt=&#34;image-20210623093004432&#34;&gt;&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
