2026年3月

mac mini 是新买的 32G,性能较强,现在很多工作都迁移到这上面了。 但是我偶尔还是会有移动性的要求,旧的 macbook m1 pro 还是继续用,只是想知道,现在有什么方案,可以让 macbook 可以远控家里的 mac mini?

编注:本文是《日本全境漫游计划》的试读文章,本栏目会以日本八大地域划分为主线,同时辅以特别专题栏目,不论是第一次赴日的游客、还是有丰富经验的旅人,都能以此栏目为参考,收获实用的的旅行建议和资料。

《日本全境漫游计划》目前正在参与少数派周年促销活动,活动期间内可以 7 折入手本指南。前往购买 >


在日本旅行,不管是四季分明的温泉乡,还是深山秘境中的一汪热汤,温泉几乎是许多旅人行程中绕不开的一站。

对当地人而言,泡汤不仅是日常生活的一部分,更是一种仪式般的身心疗愈方式;对游客而言,它既是放松的手段,也是走进日本文化肌理的独特入口。

温泉的定义

由于目前有许多旅馆、澡堂虽然标注「天然大浴场」或「露天风吕」,但其实只是普通地下水或自来水加热后的「热汤」,并不具备天然矿物成分,也没有温泉特有的疗养功效,并非真正的「温泉」。因此要想泡真正的温泉,还需要先简单了解下温泉的法律定义。

根据日本《温泉法》规定,温泉是指从地下涌出的温水、矿水、水蒸气,以及其它气体(不包括以碳氢化合物为主要成分的天然气)等地下水中,水温在 25℃ 以上的水体。

即使水温低于 25℃,只要其中含有游离二氧化碳、硫化物离子、锂离子、锶离子等 19 种规定物质之一,且达到一定浓度,也被定义为温泉。

可以看出,日本对于温泉的定义还是相对严谨的,因此要想找到真正的温泉,可以参考如下的分辨方式:

  • 查询旅馆官网或观察门口铭牌上是否标注「源泉名」「泉质」「泉温」「湧出量」等资讯;
  • 若只写「大浴場」「人工温泉」「準天然温泉」「ヘルスバス」等字样,则多为加热水;
  • 真正的温泉通常会标明泉质类型,例如「硫黄泉」「炭酸水素塩泉」「塩化物泉」等。

此外,对于温泉来说,温泉的种类也多样:从无色透明的单纯泉,到略带硫磺味的硫黄泉,甚至还有呈蓝绿色的酸性泉、铁锈色的含铁泉等。不同泉质对身体的作用也各不相同,例如:

  • 硫黄泉:有助于软化角质、改善皮肤病。
  • 碳酸氢盐泉:有「美肌汤」之称,泡完肌肤滑嫩。
  • 食盐泉(含钠泉):适合寒冷季节保温、舒缓疲劳。
  • 酸性泉:杀菌力强,适用于某些皮肤疾病,但不宜久泡;泡完后一定要仔细冲洗身体。

如果你追求的是泉质纯粹、疗效丰富的泡汤体验,还可以进一步了解「天然温泉」「源泉挂流」这些术语的意义:

  • 天然温泉(天然温泉):通常指来源于地底、具备温泉法标准的泉水。不过需要注意,有些「天然温泉」虽来自地底泉源,但在送入浴池前经过加温、加水或循环过滤处理,并不代表 100% 原汤。
  • 源泉挂流(源泉かけ流し):是温泉品质的「金字招牌」,表示温泉水直接从泉源流入浴池,不经过循环使用或再加热,使用后直接排出,更新频率高,水质新鲜。这类温泉较为稀有,常出现在历史悠久或地热资源丰富的温泉乡。
  • 加温/加水/循环过滤:即便是合格温泉,为了控制温度或水质,也可能会适度加温或稀释,并使用循环系统以维持稳定供水。

日归温泉与温泉旅馆

在初步了解了日本的温泉之后,我们不妨继续思考一个现实的问题:旅途中,我们该如何选择合适的泡汤方式?

如果你行程紧凑、预算有限,日归温泉(日帰り)无疑是最灵活、经济的选择。只需支付几百日元至两三千日元的入浴费,便可在短暂的停留中享受泡汤带来的舒适与放松,尤其适合长时间搭乘交通工具或徒步登山后的中途休息。在一些知名温泉地,提供日归选项的酒店非常多;在城市附近还有一些专门的日归浴场,里面提供吃喝洗一条龙服务,性价比颇高,这也是我目前泡温泉的主要选择方式。

不过,若你渴望的是慢生活式的深度体验,那么选择一家拥有自家源泉的温泉旅馆(温泉旅館)入住一晚,会是更惬意的方式。从穿上浴衣、漫步旅馆走廊,到在榻榻米上享用怀石料理,夜晚在安静的露天风吕中仰望星空——这是许多旅人心中理想的「泡汤」画面。尤其在冬季雪景或秋季红叶时节,能在露天温泉中与大自然融为一体,更是难得的享受。此外,还有很多温泉是只面向住宿者的,因此只有住宿才可享受到温泉设施。

即便不选择传统温泉旅馆,温泉地附近的温泉民宿也是非常不错的选择。比如图上的的民宿,位于北海道川汤温泉附近,仅需 3 万日元(1500 元人民币)就可以享受到独栋房 + 私人室外温泉的顶级享受。相对顶级温泉酒店来说,有时温泉民宿的价格会更亲民,而氛围也更自在,适合喜欢地方人情味、情侣或者家庭出行的旅人。

话说回来,泡汤方式没有绝对的优劣,关键是与你的行程节奏、预算安排和旅行风格相匹配。想节省时间和费用,就选日归温泉;想彻底放松、享受「泡 + 宿」的完整体验,不妨好好选一家值得期待的温泉旅馆。

入浴礼仪

当弄明白了温泉的定义和选项,接下来便是尊重这项古老而深厚的文化仪式——因为在日本,泡温泉不仅是「洗澡」这么简单,更是一种在「共享空间」中松弛身心的场所。作为游客,如果能提前了解一些入浴礼仪,就可以减少不必要的麻烦,获得更好的体验。

脱衣、置物、准备阶段

  • 除去男女混浴外,多数温泉设有男女分区入口,分别标示「男 」与「女 」。 如果是酒店,一般女性浴场还会独立设置一个密码,男性浴场仅需刷房卡即可进入。
  • 进入更衣室前请脱鞋,并将鞋放入指定鞋柜;如果有号码牌请将号码牌夹在拖鞋上。更衣室常设有木篮或锁柜供存放衣物。
  • 在脱衣室换好浴衣或内衣后,就可以前往淋浴区(洗浴区)进行清洗准备。

清洗身体

  • 在进入浴池前,必须认真清洗全身,包括头发、身体、脚部等,使用淋浴椅、喷头、盆子,坐姿完成清洗。
  • 冲洗时避免弄湿他人或在洗区内逗留或奔跑,注意水花和噪音控制。
  • 使用香皂、洗发水后,务必将泡沫冲净再进入浴池。因为浴池是「泡汤区」,不是继续洗澡的地方。

进入浴池前后

  • 进入浴池时通常不能穿泳衣、衣物或将毛巾浸入水中。多数温泉要求全身裸入。
  • 手巾/小毛巾可用作覆盖身体或擦拭,但不能浸入池内。一般会有浴客将毛巾折叠置于头上。
  • 头发应束起或留在水面之外,避免掉落或触及汤水。
  • 入汤后应保持安静、放松,不奔跑、不在池中游泳,这里是放松与沉静的时刻。

 特殊注意事项

  • 刺青问题:在许多温泉中,刺青仍被视为禁入标志(原因与黑帮文化有关),即便是外国旅客也应事前确认。 一般来说,有小范围纹身的游客可以进行遮盖后入场。
  • 饮酒或身体不适者慎入:温泉水温一般较高,若饮酒过度或身体状况欠佳(如高血压、心脏病、开放性伤口),建议避免或缩短入浴时间(但实际上有些浴场会在温泉旁贩售啤酒)。
  • 男女混浴:虽然传统上男女混浴曾存在,但大多数公共温泉已分区。若有混浴设施,建议事先查明是否允许泳衣或毛巾入浴。
  • 拍摄问题:原则上公共浴场不允许携带任何手机、相机设备入场。独享的私汤不受限制。

泡汤的节奏建议

  • 温泉水温通常在 40 ℃ 左右以上,建议采用「泡 -> 休 - > 泡」的循环方式,每次泡约 10 – 15 分钟为宜,中途起身喝水、冷却身体再继续。
  • 泡完后进入更衣室前可轻擦身体去除水珠,避免水滴弄湿地面,也更为礼貌。

如何寻找温泉

虽然每个人心目中的理想温泉都不一样,但无论你想找寻小众的、抑或是著名的温泉,都可以尝试通过下面的一些方法搜索。

 利用专门平台或搜索引擎过滤

  • 在日本常用的旅游订房与温泉信息网站(如 じゃらん、楽天トラベル、一休.com)中,搜索「目的地 + 温泉」关键词,然后再用「日帰り」「源泉かけ流し」「露天風呂」等条件进行筛选。
  • 也可直接通过日本秘湯を守る会(Japan Hidden Hot Springs Association)等组织的网站查看会员温泉,他们多为源泉直流、环境幽静的温泉旅馆。
  • 还可以通过排名等标签来搜索,比如「日本百名湯」,「にっぽんの温泉 100 選」等等。
  • 当然,诸如小红书此类国内平台也会有很多温泉分享;但如果你想找一些游客少的,不妨试试上述方法。

关键字帮你锁定优质温泉

寻找温泉时,可重点留意以下关键词,并尝试在搜索时复制粘贴,因为这些往往标示较高品质或特色:

  • 源泉かけ流し(源泉直接流出):无需循环、水源更新快,被视为品质优选。
  • 加水なし・加温なし:表示未经稀释、未加热或补水,更接近天然源泉状态。
  • 露天風呂(露天风吕):室外或半室外浴池,可将自然景观纳入泡汤体验。
  • 貸切風呂(包租风吕)/貸切露天:可以包场温泉,适合家庭、情侣、希望私密体验的旅人。
  • 日帰り入浴可(可日归):确认是否允许「当天入浴」而不住宿,对预算有限或行程紧凑的旅者尤为重要。
  • 交通案内/アクセス:很多位置偏僻的温泉交通不便,但是如果酒店会提供免费的接送巴士会在该页面写出。

小贴士:如何从地图与评价中读出线索

  • 抬头查泉源所在地:山脚、溪畔、海边等地形通常泉质较丰富。
  • 通过评论过滤:旅客评价中提及「源泉流出」「气泡很多」「泉质滑」「露天视野好」等词,反映真实体验。
  • 检查是否支持日帰り:许多温泉旅馆由于只住宿开放,日归入浴需打电话或查官网确认。
  • 看交通信息:是否有 JR + 巴士、是否自驾可达、是否需要步行上坡很长,这些会影响便利程度。

日本代表性温泉地介绍

日本列岛坐落在火山带上,自古以来便是温泉资源极为丰富的国家。这些温泉地有的以疗效闻名,有的靠自然美景取胜,也有的因为历史、文化或独特氛围成为人们心中的「泡汤圣地」。下面,我简单介绍下日本最具代表性的几大温泉聚集地。

大分县:别府温泉 & 由布院温泉

大分县是日本温泉涌出量和源泉数双双排名第一的「温泉大国」。

别府温泉是由「别府八汤」组成,市内处处可见蒸汽袅袅的温泉口,泉质多样,还可以体验地狱蒸、美肌汤与砂浴等特色泡汤方式。

此外还有由布院温泉位于山间盆地,氛围静雅,配套精致,适合想要远离喧嚣、享受慢生活的人。沿街有许多美术馆、甜品铺和手工艺品店,是文艺气息浓郁的温泉乡代表。

北海道:登别温泉

北海道也是首屈一指的温泉地,以丰富泉质和地热地形著称。登别温泉是位于登别市的地狱谷旁,九种泉质各异的温泉从地底不断涌出,包括硫磺泉、铁泉、明矾泉等,疗养功效广泛。周边景点如熊牧场、地狱谷步道也非常值得一游,冬季泡汤更是别有风情。

秋田县:乳头温泉乡

位于十和田八幡平国立公园深处的乳头温泉乡,是日本秘汤迷心中的圣地之一。这里由七个风格各异的温泉旅馆组成,每一处都拥有独立源泉,泉质多样、疗效丰富,是体验「汤巡(湯めぐり)」的理想之地。被原始森林环绕的露天风吕四季风景迥异,冬日雪见温泉更是梦幻。以茅草屋顶的「鹤之汤」为代表,乳头温泉乡至今保留着传统汤治文化的质朴氛围,是远离尘嚣、感受山林气息的绝佳之选。

群马县:草津温泉

被誉为「天下名汤」的草津温泉,是日本温泉知名度最高的三大温泉之一。草津温泉的泉源温度高达 50℃ 以上,有着强烈的杀菌与疗养效果。最有名的是「汤畑」——源泉喷涌的中心广场,终日蒸汽升腾,是拍照打卡圣地。传统的「汤揉(湯もみ)」文化至今保留,也能体验古法泡汤乐趣。

神奈川县:箱根温泉

靠近东京、交通便利,是关东地区最受欢迎的温泉目的地之一。箱根有二十余个温泉地区统称为「箱根温泉郷」,泉质丰富,设施完善。结合了温泉、美术馆、富士山风景与高原森林,是休闲与文化体验兼具的泡汤选择。

新潟县:越后汤泽温泉

越后汤泽是著名滑雪胜地,冬季泡汤赏雪的最佳组合。越后汤泽温泉区交通便捷,从东京搭乘新干线仅需约 1.5 小时。温泉大多建于山脚,兼具疗养与赏雪景致,部分旅馆还能眺望滑雪场。

和歌山县:白滨温泉

拥有悠久历史的海滨温泉之一,被称为「日本三古汤」之一。白滨温泉的特色在于一边泡汤一边欣赏太平洋海景,许多旅馆设有海景露天风吕。周边还有冒险世界动物园、白良滨海滩等度假资源,是家庭出游的好去处。

长野县:地狱谷野猿公苑温泉

还有一些特殊的温泉,比如长野的地狱谷,在这里你可以在这里看猴子泡温泉(人并不能泡温泉)。温泉位于山中的地狱谷野猿公苑内,每年冬季雪猴泡温泉的画面成为网络热图。虽然本身并非可供人泡的温泉,但周边如渋温泉、汤田中温泉等也是泡汤好地方。

个人推荐温泉

走访日本各地的温泉乡,是我旅途中最享受的部分之一。无论是冬日雪景中热气升腾的露天风吕,还是山林溪谷旁默默涌出的秘汤,都带给我身体的放松与内心的安宁。在众多泡汤经验中,以下几处温泉遍布全日本,虽然这些不一定是所谓的「秘境」,但都是我私心想推荐给每位读者的精选之选。

北海道:第一滝本館

官网链接

我第一次在日本泡温泉,是在北海道登别的这家第一滝本馆。那是几年前的一个冬天,外头大雪纷飞,我和朋友泡在露天温泉里,一边欣赏着被白雪覆盖的山景,一边举杯畅饮冰啤酒。热气氤氲与雪花交融,寒冷与温暖交织,那一刻的舒畅与自由让我至今难忘。也正是从那时起,我踏上了探索日本温泉的旅程。

第一滝本馆的温泉占地 5000 平方米,是目前登别规模最大的温泉之一,无论是住宿还是温泉都比较推荐。在第一滝本馆,你可以享受日本十大温泉中的五种。在源泉源头的自由流淌的泉水中,体验每种泉质的独特功效,度过一段身心焕然一新的美好时光。丰富的温泉水量和丰富的泉质,让你在酒店内享受奢华的温泉之旅,享受幸福的温泉体验。

北海道:熊の湯 羅臼

官网链接

在知床国立公园的原始森林之中,有一处被誉为「秘汤」的野趣露天温泉——熊之汤。它坐落于羅臼温泉野营场对面、国道 334 号旁的羅臼川畔,四周被原始林环抱,泡汤时不仅能感受到满满的自然包围感,更能随着四季变换,欣赏到知床森林不同的风貌。

熊之汤原本是当地渔民用来缓解劳累的天然温泉,如今却成为吸引全国秘汤爱好者前来朝圣的人气景点。这是一个「野汤」,温泉由当地志愿者管理,平日无人对应,因此需要自行携带浴巾等装备进入,非常适合想拥抱大自然、探寻秘境的朋友。

山梨县:ほったらかし温泉

官网链接

位于山梨县山梨市矢坪,海拔约  700  米的山腰地带,Hottarakashi Onsen 是一处以「绝景露天温泉」著称的日归温泉设施。 在这里,你可一边浸泡在温泉中,一边俯瞰甲府盆地、眺望远处的富士山,既可在日出时分与晨曦同浴,也可在夜晚享受被称为「星空即天花板」的壮丽星景。

温泉设有两处浴场:「こっちの湯」(Kocchi‑no‑Yu)与 「あっちの湯」(Acchi‑no‑Yu)各具特色。前者为 1999 年开设,富士山在正前方,氛围宁静沉稳;后者于 2003 年开设,浴池面积约为前者两倍,并以上帝视角俯瞰甲府盆地,最佳适合日出或夜景观赏。

特别提醒:此处允许携带纹身者入浴,无须额外遮挡。这里能看到好多日本纹身大哥,介意的朋友慎重考虑。

九州天草:天之寂酒店

官网链接

在五星级旅馆天ノ寂中,顶层 5 至 6 楼仅设有 4 间最顶级的套房,室内面积 115㎡,外附 59.2㎡ 的宽敞露台。每一间都会所配备:

室外天然温泉露天浴池,让你在房间内便能沉浸于上天草「松岛温泉(ナトリウム塩化物泉)」的疗养泉质。

室内浴场含桑拿房 + 冷水池,满足热汤之后「冷却循环」这一日式泡汤心法。

豪华双床(160×200 cm)两张,适合两人入住;配备先进设施:电视、冷藏酒柜、便携音响、咖啡机、干湿分区洗手间、免费 Wi-Fi、冷暖调节系统、毛巾暖房与保险箱等。

露台上设有舒适沙发,伴随着海风与天空,可以一边品酒一边俯瞰天草群岛和无边海景。如果你预算充裕,可以选择此处。如此顶级套房,不仅打造「房间+温泉+风景」的三重体验,更让入住者仿佛置身于私人疗养秘境;是希望在旅途中彻底放松、逃离城市喧嚣、专注于心身修复的旅人之选。

埼玉县:喜楽里 別邸

官网链接

位于埼玉县飯能市宫沢湖畔的「宮沢湖温泉 喜楽里別邸」,是一家主打「大人休闲」与景观温泉体验的日归温泉设施。 这里坐落在森林环绕与湖景相映的环境中,特别设有观景露天风吕,面朝宫沢湖及秩父山系,四季能够欣赏湖畔自然变化的景致。

泉质为弱碱性单纯温泉(加水加温),富含钠离子与碳酸氢盐离子,因此有「美肌之汤」的称号,既可帮助去除角质,让肌肤感受滑润,也具备缓解疲劳与放松身心的效果。

此外,馆内还设置了高人气的「温热房 · 岩盤浴」区,通过远红外线与岩盘加热方式促进深层汗出、代谢提升,适合想做「泡汤 + 排汗」组合体验的旅人。

枥木县·離れの湯 あけび

官网链接

位于栃木县日光市、沿著清澈的鬼怒川溪谷而建的「あけび」,是一家主打源泉掛流し的个室貸切露天温泉设施。

这里提供 10  个完全独立包场的露天浴池,每间可容纳 2-5 人,非常适合情侣、朋友或家庭一起轻松入浴。

温泉泉质为「ナトリウム・カルシウム‑硫酸塩・塩化物温泉」,弱碱性低張性泉水,触感温润,适合缓解神经痛、关节痛、冷感症、慢性皮肤病等。 浴池采用自家源泉掛流し设计,即源头温泉水直接流入、不循环回用,强调「真正的天然汤屋体验」。

秋田县:乳頭温泉郷

官网链接

位于日本秋田县仙北市、坐落于十和田・八幡平国立公园乳头山麓的乳頭温泉乡,是一处拥有悠久历史与丰富自然泉质的汤治圣地。温泉乡由七处独立温泉旅馆(包括鶴の湯温泉、妙乃湯、蟹場温泉、大釜温泉、孫六温泉、黒湯温泉与休暇村乳頭温泉郷)组成。因为每家旅馆持有不同的源泉,所以你可以购买通票,合计可体会超过十种以上泉质的温泉体验。

如果你想寻找一处真正「入山泡汤、与自然同呼吸」的温泉地,乳头温泉乡绝对值得纳入你的温泉之旅中。

青森县:黄金崎不老ふ死温泉

官网链接

坐落于黄金崎(青森县西津軽郡深浦町)海岸边,濒临广袤的日本海的黄金崎不老ふ死温泉,以「海与温泉融为一体的绝景露天风吕」著称。

这里的泉质为「含铁‑钠‑盐化物强盐泉」,温度高、保温力强,被称作「热の湯」「傷の湯」「美肌の湯」皆有其名。 源泉湧出时虽透明,但空气接触后氧化变为赤褐色,浴后体感温暖且不易湯冷め。 浴池直接贴近海岸岩石,仿佛浸泡在海里。尤其日落时分,地平线上的夕阳染红海面,景色令人屏息。

若你向往「一浴尽览海、天、湯」的极致温泉体验,黄金崎不老ふ死温泉无疑是一处标杆。赤褐色的温泉水、岩礁海岸的开放感与日落余晖构成的画面,将成为你旅途中的难忘回忆。

尾声

温泉不仅是日本人生活中的一部分,更是旅途中最能慰藉身心的存在。从热气腾腾的「汤畑」,到藏于深山人迹罕至的秘汤,每一次泡汤,都是一次与自然、与自我、与土地文化的亲密对话。

在这篇文章中,我们一同了解了温泉的定义、入浴的礼仪,也探访了那些值得前往的温泉圣地与我私藏的一些名汤。但温泉的魅力,远不止于此。不同的季节、时间、气候,都会赋予每一座温泉不同的风貌与故事。

愿你也能在某一个寒冷的清晨、或者黄昏的余光下,沉入一池暖汤之中,忘却疲惫,在蒸腾的雾气里,感受到那份只属于温泉的治愈与宁静。

    1. 软件开发行业的 AI 范式演进:从辅助工具到工程智能体
    2. Claude Code 全景入门:装好、看懂、跑起来
    3. 上下文注入:用 @ 和 ! 精准喂给 Claude 它需要的信息
    4. 记忆系统:用 CLAUDE.md 告别每次对话都要"重新认识你"
    5. 斜杠命令:把你的重复操作变成一个单词
    6. Hooks 机制:让 AI 的每一步都在你的规则里
    7. MCP:给 Claude Code 接上"外设"
    8. Skills:让 Claude 按需加载你的领域知识
    9. Sub-agents:给 Claude 分身,让专家各司其职
    10. Agent Teams:组建你的 AI 开发小队
    11. 安全与回退:给 AI 戴上"安全带"
    12. SDK 与 Headless:把 Claude 变成你的自动化引擎
    13. 上下文工程:从记忆文件到分层知识架构
    14. 模型选择与成本控制:把每一分钱花在刀刃上

    你大概已经听说过 Claude Code——一个在命令行里跑的 AI 编程工具。

    但如果你只是想"先装上试试",网上随便搜一篇教程就够了。这篇文章要做的事稍微不一样:在你装好、跑起来之后,帮你看清楚这台机器的整体构造

    知道整体构造有什么用?很简单:当你遇到问题,你知道从哪里找原因;当你想扩展功能,你知道往哪个方向想;当你读后面每篇文章,你知道那个功能"长"在系统的哪个位置。

    我们先装好,再看全景。


    第一步:装好 Claude Code

    Claude Code 是原生应用,不需要预装 Node.js 或其他运行时,直接一行命令搞定。

    macOS / Linux / WSL:

    curl -fsSL https://claude.ai/install.sh | bash

    Windows PowerShell:

    irm https://claude.ai/install.ps1 | iex

    Windows 用户需要先装好 Git for Windows,安装脚本依赖它。

    macOS 也可以用 Homebrew 安装,但不会自动更新,需要手动执行 brew upgrade claude-code

    brew install --cask claude-code

    安装完成后验证:

    claude --version

    看到版本号就好了。原生安装方式会在后台自动更新,保持在最新版本。


    第二步:选择接入方案

    Claude Code 本身只是一个"壳",负责读文件、执行命令、管理对话。真正"思考"的部分是背后接入的大语言模型。

    你有两条路:

    路线 A:Anthropic 官方 Claude API

    console.anthropic.com 注册、充值、拿到 API Key。效果最好,费用也最高。

    路线 B:国产大模型(推荐学习阶段使用)

    很多国产模型(智谱 AI、DeepSeek、通义千问等)提供兼容接口,可以直接接入 Claude Code。效果略差,但够用,费用低,网络也稳定。

    如果你喜欢命令行,手动配置环境变量:

    # 路线 A
    export ANTHROPIC_API_KEY=你的key
    
    # 路线 B(以智谱 AI 为例)
    export ANTHROPIC_BASE_URL=https://open.bigmodel.cn/api/paas/v4
    export ANTHROPIC_API_KEY=你的key

    建议把这两行加到 ~/.zshrc~/.bashrc 里,下次打开终端自动生效。

    如果你不想手动编辑配置文件,可以用 CC Switch ——一个专门管理 Claude Code 等 AI CLI 工具的桌面应用,支持 50+ 模型提供商预设,点几下就能切换,不需要记环境变量的写法。

    macOS 安装:

    brew tap farion1231/ccswitch && brew install --cask cc-switch

    Windows 和 Linux 用户去它的 Releases 页面 下载安装包。

    两种方式都能达到同样效果,选你顺手的就好。


    第三步:跑起来

    进入任意一个项目目录,输入 claude

    cd 你的项目目录
    claude

    第一次运行会提示登录或确认 API 配置,跟着提示走完就好。进入对话后,你可以试试:

    > 这个项目是做什么的?
    > 帮我列出所有 Python 文件
    > 帮我写一个 hello world 函数

    能收到回答,就说明整条链路通了。


    现在,我们来看引擎盖下面

    装好之后,大多数人就停在这里——问它问题,它给答案。这是 Claude Code 最基本的用法,但只用到了它能力的一小部分。

    Claude Code 的完整技术栈可以分成四层:

    ┌──────────────────────────────────┐
    │    Agent SDK(用代码直接驱动)    │
    ├──────────────────────────────────┤
    │  集成层:Headless 模式 + MCP     │
    ├──────────────────────────────────┤
    │  扩展层:Commands / Skills /     │
    │          SubAgents / Hooks       │
    ├──────────────────────────────────┤
    │    Memory(记忆系统)             │
    └──────────────────────────────────┘

    你现在接触到的对话交互,其实只是最上层和最下层的结合——Memory 给它背景,你问它答。中间两层,才是 Claude Code 真正强大的地方。


    第一层:Memory,持久记忆

    每次开新会话,模型本身什么都不记得。Memory 层解决的就是这个问题。

    核心文件是 CLAUDE.md,放在项目根目录。Claude Code 启动时自动读取,就像新员工入职前看手册。你写进去的技术栈、代码规范、禁止事项,它都会"记住"。

    三个层级,从广到窄:

    ~/.claude/CLAUDE.md        ← 全局(所有项目共用)
    项目根目录/CLAUDE.md       ← 项目级(当前项目)
    子目录/.claude/rules/      ← 模块级(特定目录)

    Memory 是整个系统的地基——后面所有组件的行为,都建立在这个稳定的项目认知上。


    第二层:扩展层,四个核心组件

    这一层是 Claude Code 能力的真正来源,包含四个组件。

    Commands(斜杠命令)

    你输入 /commit,Claude 就按你定义好的方式生成提交信息。

    斜杠命令本质是你写的 Markdown 文件,放在 .claude/commands/ 里。Claude 读文件,照着执行。适合固定流程——那些每次都要重复描述的操作,变成一个命令,一键触发。

    Skills(技能)

    斜杠命令需要你主动输入 /xxx。Skills 不一样——Claude 自己判断是否激活

    你说"帮我看看这段代码有没有安全问题",Claude 识别到安全审查任务,自动激活 security-review Skill,用安全专家的方式来分析——不需要你输入任何命令。

    适合需要专业判断的场景:安全分析、性能评审、架构设计。

    SubAgents(子代理)

    当任务太重,或者会产生大量噪音,Claude 可以分身出去:

    主 Claude:这个任务要跑大量测试,我创建一个子代理来处理。
    子代理:独立执行,只把结果汇报给主 Claude。

    子代理有独立的上下文,执行完销毁。主流程保持清晰,不被大量日志淹没。适合隔离执行:批量文件处理、密集测试、日志分析。

    Hooks(钩子)

    前三个组件是"Claude 做什么",Hooks 是"特定时机自动发生什么"。

    事件:Claude 即将修改某个文件
    Hook:自动运行检查脚本
    结果:有问题就阻止,没问题就放行

    Hooks 绑定在操作生命周期上——PreToolUse(工具调用前)、PostToolUse(调用后)——只要事件发生就自动触发。适合自动化守卫:格式化、安全检查、日志记录。


    第三层:集成层,连接外部世界

    Headless(无头模式)

    去掉对话界面,让 Claude 完全自动运行。这是把 Claude Code 接进 CI/CD 流水线的方式——代码提交时自动审查、合并前自动检查,不需要人盯着。

    比如在 GitLab CI 里,每次有人提 Merge Request,自动让 Claude 做代码审查:

    code-review:
      stage: review
      image: node:22
      script:
        - npm install -g @anthropic-ai/claude-code
        - claude --headless "审查本次 MR 改动的代码,重点检查安全问题和潜在 bug,用中文输出审查意见"
      rules:
        - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      variables:
        ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY  # 在 GitLab 项目设置里配好

    每次有人发起 MR,这个 job 就自动跑,Claude 看完代码把意见输出到流水线日志里。你不需要做任何手动操作。

    MCP(Model Context Protocol)

    Claude 自己会读文件、写代码,但没办法直接查你的数据库、打开浏览器。MCP 是给它接上这些外设的协议:

    Claude → MCP → 你的数据库
    Claude → MCP → Jira / Slack / Notion
    Claude → MCP → 任何你想接入的系统

    装对应的 MCP 服务器,Claude 就能操作这些外部系统,就像操作本地文件一样自然。


    第四层:Agent SDK

    当配置的方式不够灵活,可以用代码直接控制 Claude:

    from claude_agent_sdk import ClaudeSDKClient
    
    client = ClaudeSDKClient()
    result = client.query(
        prompt="分析这段代码的安全问题",
        tools=["Read", "Grep"],
        max_turns=10
    )

    这一层适合把 Claude 能力嵌入自己程序的场景。大多数读这个系列的人暂时不需要,但知道它的存在——当你需要的时候,这就是入口。


    技术选型速查

    面对一个具体需求,选哪个组件?

    需求特征选什么
    固定流程,手动触发Commands
    需要 Claude 智能判断是否介入Skills
    任务量大、会产生大量噪音SubAgents
    某个时机必须自动发生Hooks
    需要连接外部系统MCP
    需要在 CI/CD 中无人运行Headless

    组件怎么配合

    这四层不是孤立的。来看一个贴近日常的场景:你在做一个个人项目,每周想生成一份"本周做了什么"的开发日志,发到自己的 Notion 里存档。

    你只需要输入 /weekly-log,剩下的全自动:

    1. Commands 接收 /weekly-log 触发,按照你写好的指令模板启动流程。
    2. Memory 提供背景——CLAUDE.md 里写着"日志用中文,格式是:本周完成、遇到的问题、下周计划"。
    3. SubAgents 被派出去干脏活:扫描这周的 git 提交记录,整理出改了哪些文件、合并了哪些分支。主流程不用被这些细节噪音打扰。
    4. Hooks 在日志文件写入后自动触发,把文件备份一份到本地 logs/ 目录。
    5. MCP(Notion 服务器)把生成好的日志推送到你的 Notion 数据库,自动打上本周日期的标签。

    你坐在那里,喝完一杯茶,日志已经在 Notion 里了。

    这个例子没有安全漏洞、没有复杂的工程流程——就是一件普通的重复性事务。但它同样可以用这套组合拳解决,这才是 Claude Code 可组合设计的真正价值:不只是给工程师用的,也是给任何有重复工作要处理的人用的。


    本文总结

    这篇文章做了三件事:

    装好工具:Claude Code 是原生应用,一行 curl 命令安装,不依赖 Node.js。接入方案有两条路,官方 API 效果最好,国产模型够用且便宜;不想手动配环境变量的,用 CC Switch 可视化搞定。

    看清全貌:Claude Code 的底层是四层结构——Memory(持久记忆)、扩展层(Commands / Skills / SubAgents / Hooks)、集成层(Headless + MCP)、Agent SDK。你现在对话用到的只是最表层,中间两层才是真正让它变得可编程的地方。

    建立直觉:每个组件有自己的定位——固定流程用 Commands,专业判断用 Skills,隔离执行用 SubAgents,自动守卫用 Hooks,接外部系统用 MCP,无人值守用 Headless。组合起来,才是它真正的威力所在。

    后面的文章会逐个把这些组件跑通。有了这张全景图打底,你读每篇文章都知道自己在拼哪一块。


    好了,现在轮到你了

    按照文章开头的步骤装好、配好,进入你的项目目录,输入 claude

    问它"这个项目是做什么的"——它会读你的代码,给出一个真实的回答。这一刻的感受,和用网页版 ChatGPT 聊代码,是完全不同的体验。

    大家好,我是良许。

    最近在做嵌入式Linux项目的时候,经常有朋友问我关于RootFS的问题。

    比如"为什么我的板子启动不了?""文件系统怎么制作?""initramfs和rootfs有什么区别?"等等。

    今天我就系统地给大家讲讲RootFS文件系统,从原理到实践,让你彻底搞懂这个嵌入式Linux开发中的核心概念。

    1. 什么是RootFS

    1.1 RootFS的基本概念

    RootFS,全称Root File System,即根文件系统。

    它是Linux系统启动后挂载的第一个文件系统,也是整个文件系统树的根节点。

    所有其他的文件系统都会挂载在RootFS的某个目录下,形成一个统一的目录树结构。

    在嵌入式Linux系统中,RootFS的地位尤为重要。

    它包含了系统启动所需的所有基本文件,包括:

    • 系统初始化程序(如init、systemd等)
    • 基本的系统命令和工具(如ls、cp、cat等)
    • 系统库文件(如libc.so等)
    • 设备文件(/dev目录下的设备节点)
    • 配置文件(/etc目录下的各种配置)
    • 应用程序及其依赖

    1.2 RootFS在系统启动中的作用

    当Linux内核启动完成后,它会尝试挂载RootFS,然后执行RootFS中的第一个用户空间程序(通常是/sbin/init或/init)。

    这个过程是系统从内核空间过渡到用户空间的关键步骤。

    内核启动的大致流程是这样的:

    1. Bootloader加载内核到内存并启动
    2. 内核初始化硬件、内存管理、进程调度等
    3. 内核挂载RootFS
    4. 内核启动init进程(PID为1)
    5. init进程根据配置启动其他系统服务和应用程序

    如果RootFS挂载失败,内核会panic,系统无法正常启动。

    这也是为什么很多初学者在移植Linux时,经常遇到"Kernel panic - not syncing: VFS: Unable to mount root fs"这样的错误。

    2. RootFS的类型

    2.1 基于存储介质的分类

    根据存储介质的不同,RootFS可以分为以下几种类型:

    2.1.1 基于Flash的RootFS

    在嵌入式系统中,最常见的是将RootFS存储在Flash中。

    根据Flash类型的不同,又可以细分为:

    • NOR Flash RootFS:适合小容量系统,可以直接在Flash上执行代码(XIP),但容量小、价格贵。
    • NAND Flash RootFS:容量大、价格便宜,但需要文件系统支持坏块管理,常用的有JFFS2、YAFFS2、UBIFS等。
    • eMMC/SD卡 RootFS:类似于PC的硬盘,可以使用ext2/ext3/ext4等传统文件系统。

    2.1.2 基于RAM的RootFS

    有些场景下,RootFS会被加载到RAM中运行,这种方式称为initramfs或ramfs。

    优点是读写速度快,缺点是掉电数据丢失,且占用宝贵的RAM资源。

    2.1.3 基于网络的RootFS

    通过NFS(Network File System)挂载远程服务器上的目录作为RootFS,常用于开发调试阶段,方便快速更新文件系统内容。

    2.2 基于文件系统格式的分类

    2.2.1 传统文件系统

    • ext2/ext3/ext4:Linux下最常用的文件系统,适合eMMC、SD卡等块设备。
    • FAT32:兼容性好,但不支持Linux权限管理。

    2.2.2 Flash专用文件系统

    • JFFS2(Journaling Flash File System 2):较早的Flash文件系统,支持压缩和磨损均衡。
    • YAFFS2(Yet Another Flash File System 2):专为NAND Flash设计,性能较好。
    • UBIFS(Unsorted Block Image File System):目前最流行的Flash文件系统,配合UBI层使用,性能和可靠性都很好。

    2.2.3 只读压缩文件系统

    • SquashFS:高压缩比的只读文件系统,常用于嵌入式系统以节省存储空间。
    • CramFS:较早的压缩文件系统,已逐渐被SquashFS取代。

    3. RootFS的目录结构

    一个标准的Linux RootFS遵循FHS(Filesystem Hierarchy Standard)规范,主要包含以下目录:

    3.1 核心目录

    • /bin:存放基本的用户命令,如ls、cp、cat等,这些命令在单用户模式下也需要使用。
    • /sbin:存放系统管理命令,如ifconfig、reboot等,通常只有root用户才能执行。
    • /lib:存放系统库文件和内核模块,如libc.so、ld-linux.so等。
    • /etc:存放系统配置文件,如inittab、fstab、network配置等。
    • /dev:存放设备文件,如/dev/ttyS0、/dev/mtdblock0等。

    3.2 可选目录

    • /usr:存放用户程序和数据,包含/usr/bin、/usr/lib、/usr/share等子目录。
    • /var:存放经常变化的文件,如日志文件、临时文件等。
    • /tmp:存放临时文件,通常挂载为tmpfs(基于RAM)。
    • /proc:虚拟文件系统,提供内核和进程信息的接口。
    • /sys:虚拟文件系统,提供设备和驱动信息的接口。
    • /home:用户主目录。
    • /root:root用户的主目录。
    • /mnt:临时挂载点。
    • /opt:可选应用程序的安装目录。

    在嵌入式系统中,为了节省空间,通常会精简目录结构。

    比如将/usr/bin链接到/bin,将/usr/lib链接到/lib等。

    4. 制作RootFS的方法

    4.1 使用BusyBox制作最小RootFS

    BusyBox是嵌入式Linux中最常用的工具集,它将数百个常用命令集成到一个可执行文件中,大大减小了文件系统的体积。

    4.1.1 编译BusyBox

    # 下载BusyBox源码
    wget https://busybox.net/downloads/busybox-1.35.0.tar.bz2
    tar -xjf busybox-1.35.0.tar.bz2
    cd busybox-1.35.0
    
    # 配置BusyBox
    make menuconfig
    # 在配置界面中选择:
    # Settings -> Build Options -> Build BusyBox as a static binary (选中)
    # Settings -> Installation Options -> 设置安装路径
    
    # 编译并安装
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
    make install

    4.1.2 创建基本目录结构

    cd /path/to/rootfs
    mkdir -p bin sbin etc dev proc sys tmp lib usr/bin usr/sbin usr/lib var home root mnt
    
    # 复制BusyBox
    cp -a /path/to/busybox/_install/* .
    
    # 创建设备节点(需要root权限)
    sudo mknod dev/console c 5 1
    sudo mknod dev/null c 1 3

    4.1.3 添加启动脚本

    创建/etc/inittab文件:

    ::sysinit:/etc/init.d/rcS
    ::respawn:/bin/sh
    ::ctrlaltdel:/sbin/reboot
    ::shutdown:/bin/umount -a -r

    创建/etc/init.d/rcS文件:

    #!/bin/sh
    
    # 挂载proc和sys文件系统
    mount -t proc none /proc
    mount -t sysfs none /sys
    mount -t tmpfs none /tmp
    
    # 挂载devtmpfs
    mount -t devtmpfs none /dev
    
    # 设置主机名
    hostname myboard
    
    # 配置网络(根据实际情况修改)
    ifconfig eth0 192.168.1.100 netmask 255.255.255.0 up
    route add default gw 192.168.1.1
    
    echo "System initialization completed"

    记得给脚本添加执行权限:

    chmod +x etc/init.d/rcS

    4.2 使用Buildroot制作完整RootFS

    Buildroot是一个自动化构建工具,可以自动下载、编译、安装各种软件包,生成完整的RootFS。

    # 下载Buildroot
    git clone https://github.com/buildroot/buildroot.git
    cd buildroot
    
    # 选择预配置(以树莓派为例)
    make raspberrypi3_defconfig
    
    # 或者自定义配置
    make menuconfig
    
    # 开始构建
    make
    
    # 生成的文件系统在output/images目录下

    Buildroot的优点是功能强大、软件包丰富,缺点是首次编译时间较长,需要下载大量源码包。

    4.3 使用Yocto制作RootFS

    Yocto是更加专业的嵌入式Linux构建系统,适合大型项目和产品化开发。

    它使用BitBake作为构建引擎,支持层(Layer)的概念,可以方便地管理不同的配置和软件包。

    # 下载Poky(Yocto的参考发行版)
    git clone git://git.yoctoproject.org/poky
    cd poky
    
    # 初始化构建环境
    source oe-init-build-env
    
    # 编辑配置文件conf/local.conf,设置目标机器
    # MACHINE = "qemuarm"
    
    # 构建最小镜像
    bitbake core-image-minimal
    
    # 或构建完整镜像
    bitbake core-image-full-cmdline

    5. RootFS的打包和烧写

    5.1 制作文件系统镜像

    根据目标文件系统类型的不同,打包方法也不同。

    5.1.1 制作ext4镜像

    # 创建空镜像文件(大小为100MB)
    dd if=/dev/zero of=rootfs.ext4 bs=1M count=100
    
    # 格式化为ext4
    mkfs.ext4 rootfs.ext4
    
    # 挂载镜像
    sudo mkdir /mnt/rootfs
    sudo mount -o loop rootfs.ext4 /mnt/rootfs
    
    # 复制文件系统内容
    sudo cp -a /path/to/rootfs/* /mnt/rootfs/
    
    # 卸载
    sudo umount /mnt/rootfs

    5.1.2 制作UBIFS镜像

    # 创建UBIFS镜像
    mkfs.ubifs -r /path/to/rootfs -m 2048 -e 126976 -c 1024 -o rootfs.ubifs
    
    # 创建UBI镜像
    ubinize -o rootfs.ubi -m 2048 -p 128KiB ubinize.cfg

    其中ubinize.cfg内容如下:

    [ubifs]
    mode=ubi
    image=rootfs.ubifs
    vol_id=0
    vol_size=50MiB
    vol_type=dynamic
    vol_name=rootfs
    vol_flags=autoresize

    5.1.3 制作SquashFS镜像

    mksquashfs /path/to/rootfs rootfs.squashfs -comp xz

    5.2 烧写到目标板

    5.2.1 使用U-Boot烧写

    通过TFTP下载镜像并烧写到Flash:

    # 在U-Boot命令行中
    tftp 0x80000000 rootfs.ubi
    nand erase.part rootfs
    nand write 0x80000000 rootfs ${filesize}

    5.2.2 使用dd命令烧写到SD卡

    sudo dd if=rootfs.ext4 of=/dev/sdb2 bs=1M
    sync

    5.2.3 使用fastboot烧写

    fastboot flash rootfs rootfs.ext4

    6. 常见问题和解决方案

    6.1 内核无法挂载RootFS

    问题现象:系统启动时出现"Kernel panic - not syncing: VFS: Unable to mount root fs"错误。

    可能原因

    1. 内核配置中没有编译对应的文件系统支持
    2. 内核启动参数中root设备指定错误
    3. 文件系统损坏
    4. 设备驱动未正确加载

    解决方法

    • 检查内核配置,确保编译了对应的文件系统支持(如ext4、ubifs等)
    • 检查U-Boot传递给内核的bootargs参数,确保root=/dev/xxx正确
    • 重新制作文件系统镜像
    • 检查存储设备驱动是否正常工作

    6.2 init进程启动失败

    问题现象:内核成功挂载RootFS,但无法启动init进程。

    可能原因

    1. /sbin/init或/init文件不存在或没有执行权限
    2. init程序依赖的库文件缺失
    3. init程序架构与内核不匹配(如内核是ARM,但init是x86)

    解决方法

    # 检查init文件是否存在
    ls -l /sbin/init
    
    # 检查依赖库
    arm-linux-gnueabihf-readelf -d /sbin/init | grep NEEDED
    
    # 确保所有依赖库都在/lib目录下

    6.3 设备节点无法访问

    问题现象:无法访问/dev下的设备节点,如串口、网卡等。

    解决方法

    • 确保内核配置中启用了devtmpfs
    • 在启动脚本中挂载devtmpfs:
    mount -t devtmpfs none /dev
    • 或者使用mdev(BusyBox提供)动态创建设备节点:
    echo /sbin/mdev > /proc/sys/kernel/hotplug
    mdev -s

    6.4 文件系统空间不足

    问题现象:系统运行一段时间后,出现"No space left on device"错误。

    解决方法

    • 增大文件系统镜像的大小
    • 清理/tmp、/var/log等目录下的临时文件
    • 将/tmp挂载为tmpfs,避免占用Flash空间:
    mount -t tmpfs -o size=10M tmpfs /tmp
    • 使用只读文件系统(如SquashFS)+ 可写分区(如UBIFS)的组合方案

    7. RootFS优化技巧

    7.1 减小文件系统体积

    在嵌入式系统中,存储空间通常比较紧张,因此需要尽可能减小RootFS的体积。

    7.1.1 精简BusyBox

    在配置BusyBox时,只选择必需的命令和功能。

    比如如果不需要网络功能,可以去掉ping、wget等命令。

    7.1.2 裁剪库文件

    使用strip命令去除库文件和可执行文件中的调试信息:

    arm-linux-gnueabihf-strip lib/*.so
    arm-linux-gnueabihf-strip bin/*
    arm-linux-gnueabihf-strip sbin/*

    7.1.3 使用压缩文件系统

    使用SquashFS等压缩文件系统,可以将文件系统体积压缩到原来的1/3甚至更小。

    7.1.4 删除不必要的文件

    删除文档、示例、头文件等开发相关的文件:

    rm -rf usr/share/doc
    rm -rf usr/share/man
    rm -rf usr/include

    7.2 提高启动速度

    7.2.1 使用并行启动

    在init脚本中,将一些不相互依赖的服务并行启动:

    service1 &
    service2 &
    service3 &
    wait

    7.2.2 延迟加载非关键服务

    将一些非关键服务延迟到系统启动完成后再加载,优先保证核心功能可用。

    7.2.3 使用initramfs

    将RootFS打包成initramfs,直接加载到RAM中运行,可以大幅提高启动速度和运行性能。

    7.3 提高系统可靠性

    7.3.1 使用只读根文件系统

    将RootFS挂载为只读,可以防止意外断电导致文件系统损坏:

    mount -o remount,ro /

    需要写入数据时,可以使用tmpfs或单独的可写分区。

    7.3.2 使用UBIFS的原子操作

    UBIFS支持原子操作,可以保证在断电时数据的一致性。

    在关键数据写入后,调用sync确保数据已写入Flash:

    int fd = open("/data/config.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    write(fd, data, len);
    fsync(fd);  // 确保数据写入存储设备
    close(fd);
    sync();     // 同步整个文件系统

    7.3.3 实现看门狗机制

    在应用程序中实现看门狗功能,定期喂狗,防止系统死机:

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <linux/watchdog.h>
    
    int main() {
        int fd = open("/dev/watchdog", O_WRONLY);
        if (fd < 0) {
            perror("open watchdog failed");
            return -1;
        }
        
        // 设置超时时间为30秒
        int timeout = 30;
        ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
        
        while (1) {
            // 执行业务逻辑
            do_business();
            
            // 喂狗
            ioctl(fd, WDIOC_KEEPALIVE, 0);
            
            sleep(10);  // 每10秒喂一次狗
        }
        
        close(fd);
        return 0;
    }

    8. 总结

    RootFS是嵌入式Linux系统的核心组成部分,理解和掌握RootFS的制作、优化和调试技巧,对于嵌入式Linux开发至关重要。

    本文从RootFS的基本概念出发,详细介绍了RootFS的类型、目录结构、制作方法、打包烧写以及常见问题的解决方案,最后给出了一些实用的优化技巧。

    在实际项目中,我们需要根据具体的硬件平台、应用场景和性能要求,选择合适的文件系统类型和制作方法。

    对于初学者,建议从BusyBox开始,手动制作一个最小的RootFS,这样可以更深入地理解Linux系统的启动过程和文件系统的组织结构。

    随着经验的积累,再逐步使用Buildroot、Yocto等自动化工具,提高开发效率。

    希望这篇文章能帮助大家更好地理解和使用RootFS,在嵌入式Linux开发的道路上少走弯路。

    如果有任何问题,欢迎在评论区留言交流!

    更多编程学习资源

    Cloudflare 最近实施了一种新的标准化方法来处理后量子 IPsec,摒弃了之前的“密码套件膨胀”,转而采用混合 ML-KEM 交换。这一举措标志着广域网(WAN)在不要求专用硬件的情况下,将如何满足 NIST 2030 年抗量子加密的最后期限。

     

    该公司将混合模块化格基密钥封装机制(ML-KEM)引入 Cloudflare IPsec 和 Cloudflare One 设备,完成了 Cloudflare 所称的“后量子 SASE 方程”,使组织能够最终锁定私有网络流量的端到端安全,抵御“现在收集,以后解密”的攻击,即恶意行为者今天抓取加密数据并保存起来,直到量子计算机足够强大再破解它。

     

    Cloudflare 的首席执行官兼联合创始人 Matthew Prince直言不讳地表示

     

    保护互联网免受未来威胁不应该是一个复杂的负担。自 2017 年以来,我们一直在努力将后量子标准直接融入我们的网络结构。通过将这种保护扩展到我们的整个 SASE 平台,我们正在使后量子安全成为默认设置——不需要硬件升级,不需要复杂的配置,也不需要增加成本。

     

    早些时候,NIST 设定了一个严格的2030年最后期限,要求放弃 RSA 和椭圆曲线加密,转而采用抗量子算法。2024 年底,明确信号表明经典公钥加密的日子已经屈指可数。德国的BSI和英国的NCSC一直在说同样的话。

     

    Cloudflare 的方法遵循了draft-ietf-ipsecme-ikev2-mlkem草案,该草案以与 TLS 相同的方式标准化了 IPsec 的后量子密钥交换。混合设置与经典 Diffie-Hellman 并行运行 ML-KEM。可以将其视为一种双重安全:ML-KEM 处理量子威胁,Diffie-Hellman 覆盖经典攻击。

     

    IPsec 走向后量子的道路与 TLS 的旅程截然不同。早期尝试RFC 8784依赖于预共享密钥或量子密钥分发,这两种方法在实践中都不太有效。预共享密钥不提供针对量子对手的前向保密。QKD 需要专用硬件,这对于大多数部署来说是不可行的。然后RFC 9370出现了,允许同时运行多达七种不同的算法。Cloudflare 称这为“密码套件膨胀”。Palo Alto Networks 全力以赴,采用了七种以上的PQC密码套件,其中大多数与其他供应商不兼容。

     

    draft-ietf-ipsecme-ikev2-mlkem 规范最终使 IPsec 与 TLS 的运作方式保持一致。Cloudflare 在其 IPsec IKEv2 响应器中构建了混合 ML-KEM 的生产支持,并针对 strongSwan 参考实现进行了测试,以确保其正常工作。

     

    Cloudflare One Appliance 在 2 月 11 日自动升级至 2026.2.0 版本。由于该设备使用 TLS 而不是 IKEv2,更新相当直接——只需从 TLS 1.2 升级到 TLS 1.3,并内置混合 ML-KEM。

     

    Cloudflare IPsec 仍在封闭测试中,同时公司正在与第三方分支连接器供应商合作以实现互操作性。Security Brief Australia指出,Cloudflare 的全球网络中加入了高可用性路由,如果数据中心宕机,可以自动重新路由流量。

     

    现在,完整的画面包括了 TLS、MASQUE 和 IPsec 的后量子加密入站和出站。根据Cloudflare Radar的数据,超过 60%的人为生成的 TLS 流量已经使用混合 ML-KEM。

     

    所有这些都不额外收费。CISA 在其2026年 1 月的出版物中承认了密钥协议和数字签名迁移之间的分歧。Cloudflare 目前的推动重点是通过混合 ML-KEM 建立密钥。数字签名的紧迫性较小,因为它们旨在阻止拥有量子计算机的活跃对手,而这样的对手目前还不存在。

     

    原文链接:

    https://www.infoq.com/news/2026/03/cloudflare-post-quantum-ipsec/

    前两天我卖飞了两个股(横店东磁、麦加芯彩),周四卖,周五这两个股就涨停,给我造成强烈的 FOMO 情绪,比卖飞更可怕的是,情绪波动导致我当时就做了几笔冲动交易,雪上加霜。

    但既然我交易吃亏了,总得学点知识,不能白吃亏。经过思考,还真的让我有所领悟——又发现了一个常见的炒股误区。(上次发现了“跑赢大盘”的误区 https://v2ex.com/t/1195925

    所谓“卖飞”,是一个误导性很强的词,它暗示我本来能拿住股票获得暴涨受益,同时也暗示我因“小失误”而做错了,我本该有能力正确操作。这是误导,这是错误的。

    根本不存在“卖飞”,正确的、客观的事实是:我本来就不该获得该收益,我根本就没有这个能力,不是小失误,而是没有失误,这就是我这个水平的正常发挥,我的水平我的实力就这样。

    说卖飞,其实是高估了自己。

    FOMO 情绪过后,冷静下来,看看事实是什么。事实是我根本不可能知道这个股会涨停,我是事后才知道的,且我误以为自己在事前就能知道,因为表面上看起来我差一点就成功了。注意,“误以为”和“表面上”,都不是事实。

    事实是我同时买了医药、恒生科技、白酒、证券,都是亏的。当然,同时我也买了有色金属、电池、电网设备,也有涨的。重点是我买的时候根本不知道这其中哪个会涨哪个会跌,等涨了卖了之后我竟然误以为自己是“知道它会涨才买”,错了!我根本不知道它会涨,连涨跌都无法判断,我竟然误以为自己能判断它会涨停,荒谬!

    这两个涨停的股,我卖飞了的股,我误以为自己凭实力买的股,事实上我只买了一手,多么讽刺!我要是真的有能力判断它会涨停,我只买一手?甚至到了现在,在情绪上、在直觉上我还是有强烈的感觉“我凭认知买的,我本来有实力吃这个涨停”,我要用非常大的意志力,用九牛二虎之力才能强行让自己看见摆在眼前的事实:我只买了一手。

    我只买了一手,且同时我还买了一大堆亏钱的股,要看见这个事实非常困难,我已经算是很注重投资心理学、很擅长做自我分析的人了,要看见这个事实都不容易,多数人甚至可能炒股几年都没有认真思考过这个问题。

    结论:说卖飞,就是高估了自己。

    最后重复一次我自创的“笨蛋炒股原则”( https://v2ex.com/t/1194706 ):

    1. 我是笨蛋,我是笨蛋,我是笨蛋
    2. 笨蛋只知道,涨的时候卖是赚的

    第一条“我是笨蛋”要重复三次,是因为真的很难承认自己是笨蛋,反复提醒一万次都不为过。在我看来,承认自己是笨蛋,是一切学习的开端。

    接上篇帖子在 apple 香港买了台 16 寸 MacBookPro ,64G+1T 配置的,这次订单存活了 1 周,打电话给苹果客服确认了 3 次都说没问题了,眼看下周六就要拿到货了,突然给我取消了。

    我这次下单:

    • 收货地址用的香港居民区地址+香港手机号
    • 教育优惠审核也通过
    • 下单用的香港发行的 visa 卡(zabank)

    我现在完全懵逼,看不出问题出在哪里了...

    我在想实在不行,我去香港线下的 apple store 买吧,不知道我这个配置的,能在线下买到吗?有没有懂的好兄弟。

    Safari 浏览器 2026-03-14 08.52.31
    Safari 浏览器 2026-03-14 08.52.54

    AWS 最近宣布支持在运行 KVM 或 Hyper-V 的虚拟化 EC2 实例中嵌套虚拟机。这是社区期待已久的功能,新选项使得可以在支持的 C8i、M8i 和 R8i 实例上进行应用仿真和硬件仿真等用例。

     

    开发者可以使用这个功能来运行移动应用模拟器、模拟汽车硬件,并在 Windows 工作站上使用 Windows Subsystem for Linux(WSL)。根据文档,Nitro 系统将处理器特性(如 Intel VT-x)暴露给实例,允许它在内部运行虚拟机。

     

    嵌套虚拟化的架构有三层:物理 AWS 基础设施和 Nitro 虚拟机监视器(L0)、运行自己虚拟机监视器的 EC2 实例(L1)以及在该实例内部运行的虚拟机(L2)。新功能支持在 C8i、M8i 和 R8i 实例上使用 KVM 和 Hyper-V。AWS 的工程总监 Ioannis Aslanidis写道

     

    这种能力使开发者和企业能够构建灵活的、嵌套的环境,使用广泛的标准虚拟 EC2 实例类型。

     

    该功能一直是社区的长期需求,2018年有开发者在 Reddit 上写道:

     

    在 Azure 中,我可以在我的虚拟机中运行 KVM,这是一种称为嵌套虚拟化的技术。亚马逊在允许在 EC2 中使用 HyperV/VMware/KVM 方面有任何进展吗?

     

    大多数关于新功能的评论都表达了同样的观点:Meta 的生产工程师 Rolf Neugebauer 写道,“你们怎么花了这么长时间?”而 Igor Sfiligoi 补充道:“直到现在,这真的是不可能的?”在一个热门的Hacker News帖子中,谷歌的软件工程师 Michael Boulos 写道:

     

    我感觉得到了证实:几年前,我们为让嵌套虚拟化在 GCE 上运行良好投入了大量的精力,我很高兴听到 AWS 也在跟进。你可以告诉人们去做别的事情,可能有一个单独的自然解决方案,等等,但有时你愿意牺牲一些峰值性能,只是为了拥有操作和控制的一致性。

     

    Render 的创始人兼首席执行官Anurag Goel补充道:

     

    这是一个大事件,因为现在你可以在 AWS VM 中运行 Firecracker/其他微虚拟机,而不是昂贵的 AWS 裸机实例。

     

    AWS 的高级解决方案架构师 Guillermo Ruiz 测试了在实例内运行Firecracker微虚拟机,并对未来的基准测试做出了承诺。Ruiz 写道:

     

    对于任何寻求隔离、Lambda 风格的运行时,或者只是从性能和密度的角度比较微虚拟机与容器的人来说,这是一个有趣的角度。

     

    过去,运行 EC2 上的嵌套虚拟化的唯一选择是使用裸机实例,即没有虚拟机监视器的物理服务器。许多开发者转而使用 EC2 Mac 实例,这是最小且最便宜的裸机选项,作为一种变通方法。现在启用嵌套虚拟化是一个在启动时设置的 API 选项,例如:

     

    aws ec2 run-instances \    --image-id ami-0abcdef1234567890 \    --instance-type r8i.4xlarge \    --cpu-options "NestedVirtualization=enabled" \    --key-name my-key-pair \    --placement "Tenancy=host"
    复制代码

     

    AWS 仍然建议,运行需要硬件虚拟化的工作负载、对性能敏感或需要低延迟的客户应该继续使用裸机实例,而不是嵌套虚拟化。

     

    嵌套虚拟化在所有区域的 C8i、M8i 和 R8i 实例类型上都可用;Graviton 实例目前尚不支持。KVM 和 Hyper-V 是唯一受支持的 L1 虚拟机监视器。

     

    原文链接:

    https://www.infoq.com/news/2026/03/aws-ec2-nested-virtualization/

    利益相关声明:文中包含营销(如促销活动)和推广(如返利链接)信息

    少数派 14 周年庆,我们联手 Sonos 带来一场硬核团购。这不仅是一次难得的价格优惠,更是一次关于声音体验的全面升级。团购于今日(2026 年 3 月 14 日)9:00 准时开启,持续至今晚 21:00,数量极其有限,具体价格以及选购指南将在本文逐一揭晓。

    随身音频的新尝试:Sonos Ace

    作为 Sonos 生态的首款头戴式耳机,它真正特别的地方在于,通过 Wi-Fi 与 Sonos 条形音响(如 Arc、Beam)联动,将电视播放的杜比全景声音效无缝「流转」到耳机端。这意味着,深夜想看大片又不愿打扰家人时,你仍能享受到完整的沉浸式环绕声体验。

    在设计上,Sonos Ace 保持了品牌一贯的极简美学,312 克的重量配合磁吸可更换耳罩,兼顾了佩戴舒适度与耐用性。支持蓝牙 5.4 与高通 aptX Lossless 无损传输(Android 用户友好),同时保留了 3.5mm 有线接口,满足不同设备的需求。

     

    家用音响的核心力量:Era 100 与 Era 300

    如果你正在寻找一款能够融入日常生活的无线音箱,Era 100 是目前 Sonos 家族中更为均衡的选择。作为 Sonos One 的继任者,Era 100 配备了两个斜置高音单元和一个中低音单元,立体声分离度远超单声道设计的同类产品。它支持通过 AirPlay 2 与苹果生态无缝衔接,也支持蓝牙直连,甚至可通过 USB-C 接口外接音频源。Trueplay 调音技术能根据房间声学特性自动优化 EQ,无论你把它放在书架、厨房还是床头,都能获得一致的声音表现。

     

    而 Era 300 则是为「空间音频」而生的产物。它独特的沙漏造型并非为了标新立异,而是为了容纳四个高音单元与两个低音单元,从而实现真正的杜比全景声音乐回放。当你播放全景声曲目时,Era 300 能够营造出超越物理箱体限制的声场——声音不仅从前方传来,更从两侧和上方包围你。如果是追求沉浸感的音乐爱好者,不妨了解一下。

     

    高保真立体声的坚守:Sonos Five

    在多数厂商转向多单元虚拟环绕的今天,Sonos Five 依然代表着品牌对传统立体声音质的理解。拥有三个高频单元和三个中低频单元,专门为音乐播放优化,声场开阔度与动态表现在无线音箱中属于第一梯队。如果你愿意一次入手两只,它们可以配对为真正的立体声系统,左右声道分离带来的临场感,足以媲美不少传统 Hi-Fi 组合。值得一提的是,Five 支持横向或竖向摆放,内置传感器会自动调整声道配置——竖放时切换为单声道,适合背景音乐;横放时则发挥立体声优势。

     

    家庭影院的基石:Arc Ultra 与 Beam G2

    对于客厅娱乐而言,条形音响是整套系统的核心。Sonos Arc Ultra 内置 14 个单元,包括 7 个高音、6 个中低音,以及一个采用 Sound Motion 技术的新型低音单元。这一设计的突破在于,它让条形音响在不依赖外置低音炮的情况下,也能输出足够扎实的低频 。9.1.4 声道的虚拟全景声表现,配合 HDMI eARC 直连电视,无论是 Netflix 流媒体还是蓝光原盘,都能获得清晰的对白与富有包围感的环境音效。

     

    如果客厅空间有限,或是更看重性价比,Sonos Beam G2 会是更务实的选择。它体积更小巧,但仍支持杜比全景声虚拟化,并且同样具备 HDMI eARC 接口和 AirPlay 2 支持。对于中小户型而言,Beam G2 能在不占据过多视觉空间的前提下,大幅提升电视自带音响的体验。

     

    低频的补充:Sub 4 与 Sub Mini

    任何音响系统,低频都是营造氛围感的关键。Sonos Sub 4 是目前该品牌最新的旗舰低音炮,采用双对立低音单元设计,通过相互抵消震动来避免箱体抖动,只输出干净有力的低频。与 Arc Ultra 搭配时,它能补足极低频的物理冲击感——比如爆炸的震感、电影配乐中的超低频铺垫 。

     

    而 Sub Mini 则是为中小空间或 Beam、Era 100 用户准备的「低频增强器」。它的圆柱形设计更为紧凑,但双低音单元的对置结构依然保留了 Sonos 低音炮的核心技术特征 。如果你已经拥有 Beam G2 或 Era 100,且觉得看电影时低频还不够过瘾,Sub Mini 是性价比很高的升级路径。

     

    上述产品都将于今日在少数派商城开启限时秒杀。 无论你是想补齐家中的最后一块音频拼图,还是第一次尝试构建无线音响系统,这都是今年不可错过的时机。

    > 下载 少数派 2.0 客户端、关注 少数派公众号,解锁全新阅读体验 📰

    > 实用、好用的 正版软件,少数派为你呈现 🚀

      CCleaner是一款系统优化和隐私保护工具,‌它可以帮助用户清理Windows系统中的垃圾文件、‌无效注册表项以及浏览器缓存等,‌从而提高系统的运行速度并保护用户隐私。‌

      一、准备工作

      安装包下载:https://pan.quark.cn/s/e7e6b24a1f4e  ,先下载好 CCleaner 压缩包(内含可执行程序),保存到电脑本地。

      二、启动 CCleaner

      1. 解压安装包

        找到下载的 CCleaner压缩包,右键点击 → 选择【解压到 CCleaner】。

      2. 打开解压目录

        双击打开解压后的【CCleaner】文件夹。

      3. 以管理员身份运行

        右键 CCleaner程序 →【以管理员身份运行】(避免权限不足导致功能受限)。

      三、验证启动

      成功打开 CCleaner 主界面,即可开始使用清理、优化等功能。

      简介

      如果说 Span<T>.NET 高性能内存体系里最亮眼的类型,那么 Memory<T> 就是它最重要的搭档。

      很多人学完 Span<T> 后,马上会遇到几个现实问题:

      • 为什么 Span<T> 不能做类字段?
      • 为什么 Span<T> 不能跨 await
      • 为什么异步 IO 场景里,很多 API 更喜欢 Memory<T> / ReadOnlyMemory<T>

      答案基本都指向同一个类型:

      Memory<T>

      一句话先说透:

      Span<T> 更适合同步、短生命周期、高性能内存操作;Memory<T> 更适合需要跨异步边界、跨组件传递、或需要长期持有的内存视图。

      如果你把 Span<T> 理解成“只能活在当前同步作用域里的高性能视图”,那 Memory<T> 就可以理解成:

      更适合活在堆上、可以跨 await 传递的内存视图。

      为什么需要 Memory<T>

      先看一个典型问题:

      async Task ReadAsync(Stream stream)
      {
          Span<byte> buffer = stackalloc byte[1024]; // 这里就不行
          await stream.ReadAsync(buffer);
      }

      这类代码之所以不成立,不是因为缓冲区写法不优雅,而是因为:

      • Span<T>ref struct
      • 它不能安全地跨异步状态机边界
      • await 可能让方法状态机和局部变量提升到堆上

      这时就需要一种“能表示连续内存,又能安全地跨异步边界传递”的类型。

      这就是 Memory<T> 诞生的核心动机。

      Memory<T> 到底是什么?

      你可以先用一句最直白的话理解:

      Memory<T> 是一段连续内存的可持久视图。

      Span<T> 一样,它通常也不拥有底层数据本身,而是“指向”一段已有的连续内存。

      但和 Span<T> 不同的是,它没有 ref struct 的那层严格限制,因此:

      • 它可以做字段;
      • 可以放到集合里;
      • 可以作为返回值长期传递;
      • 可以跨 await 使用。

      对应的只读版本是:

      ReadOnlyMemory<T>

      所以你可以把这两个类型先记成:

      类型定位
      Span<T>同步短生命周期高性能视图
      Memory<T>可跨异步、可长期持有的内存视图

      Memory<T>Span<T> 到底是什么关系?

      这是最核心的一组关系。

      可以先记这张表:

      类型是否 ref struct能否跨 await能否做字段典型用途
      Span<T>同步高性能处理
      ReadOnlySpan<T>同步只读切片
      Memory<T>异步或长期持有
      ReadOnlyMemory<T>异步只读视图

      一个非常实用的理解方式是:

      • Memory<T> 负责“持有和传递”
      • Span<T> 负责“实际操作”

      所以实际代码里经常是这样:

      Memory<byte> memory = new byte[1024];
      Span<byte> span = memory.Span;

      也就是说:

      • Memory<T> 表达这段内存可以跨作用域存活;
      • 真要读写它时,再通过 .Span 拿到高性能操作视图。

      Memory<T> 的本质长什么样?

      概念上,Memory<T> 也可以理解成:

      • 某个底层内存来源;
      • 起始偏移;
      • 长度。

      你可以把它想象成:

      (object/reference, index, length)

      它本质上仍然是视图,不是所有权本体。

      这点非常重要,因为它意味着:

      • Memory<T> 自己不负责发明一块新内存;
      • 它只是对原始内存的一层包装;
      • 你仍然要关心底层内存的生命周期。

      最常见的创建方式

      1. 从数组创建

      这是最常见的用法。

      byte[] bytes = new byte[1024];
      
      Memory<byte> memory1 = bytes;
      Memory<byte> memory2 = bytes.AsMemory();
      Memory<byte> memory3 = bytes.AsMemory(100, 200);

      这里:

      • memory1 指向整个数组;
      • memory3 指向数组中 [100..300) 那一段;
      • 没有发生数据复制。

      2. 从字符串创建只读内存视图

      字符串是不可变的,所以这里通常是:

      ReadOnlyMemory<char> memory = "Hello".AsMemory();
      ReadOnlyMemory<char> world = "Hello World".AsMemory(6, 5);

      ReadOnlySpan<char> 一样,它适合只读场景,但比 ReadOnlySpan<char> 更适合跨异步边界或长期存放。

      3. 从 MemoryPool<T> 获取

      这在高性能场景里非常常见。

      using System.Buffers;
      
      using IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(4096);
      Memory<byte> buffer = owner.Memory.Slice(0, 4096);

      这里的关键点不是语法,而是:

      • MemoryPool<T> 提供可复用内存块;
      • IMemoryOwner<T> 表示这块内存的所有者;
      • owner.Memory 给你的是对应的 Memory<T> 视图;
      • 用完后必须释放 owner,否则这块内存不能正确归还。

      常见操作

      切片 Slice

      Memory<byte> buffer = new byte[100];
      Memory<byte> body = buffer.Slice(10, 20);

      Span<T> 一样:

      • Slice 只是创建新的视图;
      • 不会复制底层数据。

      获取 Span<T>

      Memory<byte> memory = new byte[10];
      Span<byte> span = memory.Span;
      span[0] = 42;

      这是 Memory<T> 最核心的桥梁。

      很多代码的模式本质上都是:

      Memory<T> -> .Span -> 真正操作

      只读转换

      Memory<byte> writable = new byte[16];
      ReadOnlyMemory<byte> readOnly = writable;

      Memory<T> 可以很自然地转成只读版本。

      一个最重要的结论:传递用 Memory<T>,处理用 Span<T>

      这是最值得记住的一句话。

      例如异步读取:

      async Task<int> ReadDataAsync(Stream stream, Memory<byte> buffer)
      {
          return await stream.ReadAsync(buffer);
      }

      这里用 Memory<byte> 是因为:

      • 这个参数要跨 await
      • API 需要一个可以安全异步传递的内存视图

      但如果你在同步代码里真正要处理数据:

      static void ProcessBuffer(Span<byte> buffer)
      {
          buffer[0] = 1;
      }

      就更适合直接用 Span<byte>

      所以你会经常看到一种组合方式:

      async Task HandleAsync(Stream stream, Memory<byte> buffer)
      {
          int bytesRead = await stream.ReadAsync(buffer);
          ProcessBuffer(buffer.Span[..bytesRead]);
      }

      这正是 Memory<T>Span<T> 的典型协作方式。

      为什么 Memory<T> 能跨 await

      因为它不是 ref struct

      更直白地说:

      • Memory<T> 本身可以安全地存在堆上;
      • 它可以被异步状态机持有;
      • 因此它能作为 async 方法里的变量、参数、字段存在。

      但这里要注意一件非常重要的事:

      能跨 await 的是 Memory<T>,不是 Memory<T>.Span

      例如下面这种写法仍然是不对的:

      async Task BadAsync(Memory<byte> memory)
      {
          Span<byte> span = memory.Span;
          await Task.Delay(1);
          span[0] = 1; // 不应该这样写
      }

      原因是:

      • span 依旧是 Span<byte>
      • Span<byte> 依旧不能跨 await

      正确思路是:

      • 先持有 Memory<T>
      • 等需要同步处理时,再临时取 .Span

      例如:

      async Task GoodAsync(Memory<byte> memory)
      {
          await Task.Delay(1);
          memory.Span[0] = 1;
      }

      这里 .Span 的使用没有跨过 await,因此是安全的。

      为什么 Memory<T> 能做字段?

      因为它可以安全地活在堆上。

      例如:

      public sealed class BufferHolder
      {
          public Memory<byte> Buffer { get; }
      
          public BufferHolder(byte[] bytes)
          {
              Buffer = bytes;
          }
      }

      这在 Span<T> 里是不成立的。

      这也是 Memory<T> 最典型的适用场景之一:

      • 某个类需要持有一段内存视图;
      • 但又不想总是暴露完整数组;
      • 或者希望保留切片后的某段区域。

      Memory<T> 不等于“拥有内存”

      这是一个很容易忽略,但非常关键的点。

      Memory<T> 只是视图,不是所有者。

      例如:

      byte[] bytes = new byte[100];
      Memory<byte> memory = bytes.AsMemory(10, 20);

      这里真正拥有数据的是:

      bytes

      不是:

      memory

      同理,如果你用的是内存池:

      using IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(1024);
      Memory<byte> memory = owner.Memory;

      真正负责生命周期的是:

      owner

      不是:

      memory

      所以一旦 owner.Dispose(),你就不应该再继续使用这段 Memory<byte>

      MemoryPool<T>IMemoryOwner<T> 为什么经常和 Memory<T> 一起出现?

      因为 Memory<T> 解决的是“视图表达”,而 MemoryPool<T> 解决的是“底层内存复用”。

      它们组合起来非常适合这些场景:

      • 网络服务器;
      • 高吞吐文件处理;
      • 大量临时缓冲区;
      • 希望减少 GC 压力。

      典型写法:

      using System.Buffers;
      
      async Task<int> ReadOnceAsync(Stream stream)
      {
          using IMemoryOwner<byte> owner = MemoryPool<byte>.Shared.Rent(4096);
          Memory<byte> buffer = owner.Memory.Slice(0, 4096);
      
          int bytesRead = await stream.ReadAsync(buffer);
      
          Process(buffer.Span[..bytesRead]);
          return bytesRead;
      }
      
      static void Process(ReadOnlySpan<byte> data)
      {
          // 同步处理
      }

      这段代码的价值在于:

      • 通过 MemoryPool<T> 避免反复分配新数组;
      • 通过 Memory<T> 安全地跨异步传递;
      • 通过 .Span 在同步处理阶段保持高性能。

      ReadOnlyMemory<T> 的定位

      如果你的 API 本来就不希望调用方修改数据,那么应该优先考虑:

      ReadOnlyMemory<T>

      例如:

      public sealed class Message
      {
          public ReadOnlyMemory<byte> Payload { get; }
      
          public Message(ReadOnlyMemory<byte> payload)
          {
              Payload = payload;
          }
      }

      这个设计表达得更清楚:

      • 这是一段需要长期持有的内存视图;
      • 但调用方不应该修改它。

      典型使用场景

      1. 异步 IO

      这是 Memory<T> 最典型的主场。

      例如:

      • Stream.ReadAsync(Memory<byte>)
      • Socket.ReceiveAsync(Memory<byte>)
      • PipeReader / Pipelines

      这些 API 本身就天然适合 Memory<T>

      2. 需要长期持有某段缓冲区

      比如:

      • 某个对象内部保留消息体的一段视图;
      • 某个组件缓存一段数据窗口;
      • 某个解析器分阶段传递缓冲区。

      3. 只想暴露一段视图,不想暴露整个数组

      这时 Memory<T> / ReadOnlyMemory<T> 往往比直接返回 byte[] 更合适。

      4. 与内存池配合减少分配

      这在高性能系统里非常常见。

      Memory<T>、数组、ArraySegment<T> 怎么选?

      这是一个很实际的问题。

      用数组

      适合:

      • 你明确拥有这块数据;
      • 生命周期长;
      • 只是普通业务代码;
      • 不需要强调切片视图语义。

      ArraySegment<T>

      它也是“数组的一段视图”,比 Memory<T> 更早。

      但它的问题是:

      • 只适用于数组;
      • 表达能力比 Memory<T> 更窄;
      • 和现代 Span / Memory API 体系配合不如后者自然。

      Memory<T>

      适合:

      • 你要表达“这是内存视图,不是完整数组”;
      • 需要跨异步边界;
      • 想和 Span<T> / MemoryPool<T> 统一协作。

      所以今天的新代码里,如果场景允许,Memory<T> 往往比 ArraySegment<T> 更现代、更统一。

      Memory<T> 的几个常见坑

      1. 跨 await 持有 .Span

      前面已经说过,这是最常见的问题之一。

      记住:

      • 可以跨 await 的是 Memory<T>
      • 不是 Memory<T>.Span

      2. 忘记管理底层所有权

      如果 Memory<T> 来自 MemoryPool<T> 或自定义 owner,那么真正要管理的是 owner 的生命周期。

      3. 把 Memory<T> 当成拥有者

      它只是视图,不负责释放底层资源。

      4. 明明只读却还暴露 Memory<T>

      如果不需要写权限,就优先用 ReadOnlyMemory<T>

      5. 在纯同步高性能路径里滥用 Memory<T>

      如果根本不需要跨异步边界,也不需要做字段,很多时候直接用 Span<T> / ReadOnlySpan<T> 更简单直接。

      一套比较务实的实践建议

      如果你准备在项目里正确使用 Memory<T>,下面这些建议很实用:

      • 只在需要跨 await、做字段或长期持有时使用 Memory<T>
      • 真正做同步读写时,优先临时取 .Span 处理;
      • 输入只读数据时,优先考虑 ReadOnlyMemory<T>
      • 需要内存复用时,优先考虑 MemoryPool<T> + IMemoryOwner<T>
      • 不要把 Memory<T> 和底层所有权混为一谈;
      • 如果场景纯同步短生命周期,优先考虑 Span<T>

      总结

      Memory<T> 的本质,不是“能跨异步的 Span<T> 这么简单”,而是:

      它是 .NET 内存体系里那个负责“可持久视图表达”的类型。

      你可以这样理解它:

      • Span<T> 负责同步高性能处理;
      • ReadOnlySpan<T> 负责同步只读处理;
      • Memory<T> 负责跨异步、跨组件、跨生命周期地传递视图;
      • ReadOnlyMemory<T> 负责只读的长期视图表达。

      如果你在做这些事情:

      • 异步 IO
      • 缓冲区传递
      • 内存池复用
      • 需要字段持有某段内存
      • 想统一 Span 和异步 API 的边界

      Memory<T> 基本就是必须掌握的一项基础能力。

      ‌‌‌‌‌ReNamer是一款功能强大且灵活的文件批量重命名工具,支持多种重命名规则,包括添加前缀、后缀、替换字符串、更改大小写、移除字符等。

      一、准备工作

      安装包下载:https://pan.quark.cn/s/946826c92eed ,先下载好 ReNamer 压缩包(内含可执行程序),保存到电脑本地。

      二、安装 ReNamer

      1. 解压安装包

        找到下载的 ReNamer压缩包,右键点击 → 选择【解压到 ReNamer】。

      2. 运行程序

        打开解压后的文件夹,双击 ReNamer可执行文件即可启动软件。

      三、验证安装

      成功打开 ReNamer 主界面,说明安装完成!

      前言

      为了庆祝自己的工具站在 4 年没动的情况用 codex 一天重构换了血,也顺便开源了一下 , 所以抽个奖

      开源地址: https://github.com/Licoy/utils.fun

      在线使用:https://utils.fun

      (如果觉得站点不错可以给个小小的 star✨)

      抽奖内容

      chatgpt team 车位 * 1 ,1 个月无质保

      开奖时间

      北京时间 3 月 14 晚 23 点

      抽奖条件

      评论即可参与抽奖,多次评论只会最早一次的评论生效

      我正常行驶,没有超速,也没有龟速,没有加速,也没有急刹。我在直行道,对方在左转道,红绿灯前面突然从左转道压实线向直行道变道给我撞了。

      下车他说他急着接孩子,先留个电话,后面走快处,他全责就行了。当时晚高峰,后面车特别多,看了下刮趁也不严重,我也还有事,就开走了。

      我以为的快速处理是 12123 上面有个视频报案,我以为把当时事故照片视频传上去就行了,晚上回家看了看,好像不是这样的?想问问我是被忽悠了吗?快处是个啥?

      已经我现在该怎么处理去?我有很清晰的行车记录,他压实线变道给我撞了,车牌也很清晰

      一、安装 Office

      1. 解压安装文件

        安装包下载:https://pan.quark.cn/s/672a1233486c   ,找到下载的 Office 安装包,右键点击 → 选择【解压到当前文件夹】。

      2. 运行安装程序

        打开解压后的文件夹,找到 setup安装程序,右键 →【以管理员身份运行】(避免权限不足导致安装失败)。

      3. 等待安装完成

        安装过程中请耐心等待进度条走完,期间不要关闭安装窗口。

      4. 结束安装向导

        安装完成后,点击【关闭】退出安装界面。

      二、激活 Office

      1. 运行激活程序

        返回解压的 Office 文件夹,找到激活程序,右键 →【以管理员身份运行】。

      2. 等待激活结果

        运行后请等待程序执行,直到出现类似“激活成功”的提示界面。

      三、验证与使用

      1. 创建 Word 文档

        在桌面或开始菜单找到 Word 图标,点击【新建】→ 选择【空白文档】。

      2. 打开 Word 文档

        双击新建的 Word 文档,成功进入编辑界面,说明 Office 安装与激活完成!

      多年来一直用 “主密钥 + 平台名称(如 google 、baidu 、qq 等)” 的方式生成各类密码。好处是只需要记住一个密钥,输入对应名称就能算出密码,而且每个网站、App 的密码都不一样,不用担心一个泄露导致全部失守。缺点是没法直接背下来,每次都要现查,但常用的那些用久了也会自动记住。比如我的银行卡、微信、支付宝支付密码全都不同,现在也早就记熟了。

      最近重新将这个工具实现迁移到自己的工具箱了: https://github.com/liriliri/tinker

      密码生成

      另外还有一些网站生成的 token ,证书没法使用这种方式则会另外使用 keepass 存储,这次也实现了一个简单的界面工具来编辑查看。目前还比较基础,随着使用会不断完善。

      密码管理器

      所有工具均开源,本地桌面运行,不会上传任何数据,断网可运行,有兴趣的可以试试看。

      openrouter 都拿不到的低价,要么就是临时号组集群要么就是掺水模型,哪有啥特价啊