我用 Redis 加了分布式锁保护临界区,以为万无一失,结果偶发两个进程同时进了临界区、一个进程还把别人的锁给删了:一次分布式锁实现陷阱的深度复盘

我有段临界区代码用 Redis 加了分布式锁保护:SET lock NX EX 30 抢锁、处理完 DEL 释放,以为万无一失。可线上偶发两个进程同时进入临界区的数据错乱,有时还有一个进程把另一个进程正持有的锁删了。推演时序才看明白这锁有两个致命漏洞:漏洞一,锁 EX 30 过期了但业务还没跑完,锁自动释放、B 抢到、A 和 B 同时在临界区;漏洞二,释放时直接 DEL 没校验是不是自己的锁,A 跑完那个 del 删的其实是已被 B 重新持有的锁。根因是分布式锁不只是 SET NX 抢 + DEL 释放这么简单,要正确处理持锁超时和只释放自己的锁。这篇复盘从故障现场讲到分布式锁要解决的防死锁/持锁超时/只释放自己的锁/原子性几个关键问题,再到唯一 value + Lua 原子释放 + 看门狗续期、优先用 Redisson、关键业务业务层加幂等兜底的完整正解,以及功力在 unhappy path、看似简单的东西在分布式下是难题、不可靠的保护比没有保护更危险别被虚假安全感麻痹的认知。

我用 Redis 加了分布式锁保护临界区,以为万无一失,结果偶发两个进程同时进了临界区、一个进程还把别人的锁给删了:一次分布式锁实现陷阱的深度复盘

那个并发问题是数据偶发错乱才暴露的:我有段临界区代码(同一资源同一时刻只能一个进程处理),用 Redis 加了个"分布式锁"来保护:SET lock_key 1 NX EX 30 抢锁、处理完 DEL lock_key 释放。我以为这就万无一失了。可线上偶发:明明加了锁,却出现了两个进程同时进入临界区的数据错乱;更诡异的是,有时一个进程把另一个进程正持有的锁给删了。我对着这"加了锁还并发"的怪事查了好久,推演了时序,才看明白,后背发凉:我这个"分布式锁"有两个致命漏洞。漏洞一:锁过期时间(EX 30)到了,但业务还没处理完。我设了锁 30 秒自动过期(为了防止持锁进程崩了导致死锁,这本身是对的);可如果进程 A 的业务执行超过了 30 秒,锁就自动过期释放了,而 A 还在临界区里跑;此时进程 B 来抢锁,锁已过期、B 抢到了,于是 A 和 B 同时在临界区里——锁形同虚设;漏洞二:释放锁时,直接 DEL lock_key,没check 这把锁是不是自己的。接着上面:A 终于跑完了,执行 DEL lock_key——可这把锁此刻已经是 B 的了(A 的早过期、B 重新加的),A 这一删,把 B 的锁删掉了;于是 B 的临界区又失去了保护,C 又能进来……连锁崩坏。根本原因是:分布式锁不只是"SET NX 抢、DEL 释放"这么简单,它要正确处理"持锁超时"和"只能释放自己的锁"这两个关键问题。问题的根,是分布式锁实现有缺陷:锁过期了业务没完成致两进程同时进临界区、释放时不校验所有权而误删了别人的锁。这篇就把这次"分布式锁实现陷阱"的坑,从头到尾复盘一遍。

故障现场:锁过期 + 误删别人的锁

问题在于锁过期了业务还没完成、且释放时直接 DEL 没校验所有权:

// ✗ 出问题的分布式锁: 看似没问题, 实则两个致命漏洞
public void doWork() {
    // 抢锁: SET lock NX EX 30 (不存在才设, 30秒过期)
    boolean locked = redis.set("lock_key", "1", "NX", "EX", 30);
    if (!locked) return;   // 没抢到, 退出
    try {
        criticalSection();  // ✗ 临界区业务; 如果它执行超过30秒...
    } finally {
        redis.del("lock_key");  // ✗ 释放锁: 直接DEL, 没check是不是自己的锁!
    }
}

// 漏洞一: 锁过期了, 业务还没跑完
//   - 设EX 30是对的(防止持锁进程崩了, 锁永不释放=死锁);
//   - 但若 criticalSection() 跑了超过30秒:
//     * 第30秒, 锁自动过期释放;
//     * 进程A还在临界区里跑;
//     * 进程B此时来抢锁 → 锁已过期, B抢到了 → A和B【同时在临界区】→ 锁失效, 数据错乱!

// 漏洞二: 释放锁时直接DEL, 删了别人的锁
//   - 接上: A终于跑完, 执行 del("lock_key");
//   - 可此刻这把锁已经是B的了(A的过期、B重新SET的);
//   - A这个del → 把【B的锁】删掉了! → B的临界区失去保护 → C又能进来 → 连锁崩坏。

// 时序推演:
//   T0:  A 抢到锁(EX 30)
//   T30: 锁过期(A业务还没完)
//   T31: B 抢到锁(锁已过期)         ← A、B同时在临界区!
//   T35: A 业务完成, del lock_key    ← 删的是B的锁!
//   T36: C 抢到锁                    ← 又一个进来, B、C同时...

// 关键: 分布式锁不是"SET NX抢+DEL释放"这么简单; 锁过期但业务没完会让多进程同时进临界区,
//       释放时不校验所有权会误删别人的锁 —— 要处理"持锁超时"和"只删自己的锁"。

第一次推演出"A 的锁过期了、B 进来了,A 跑完又把 B 的锁删了"时,我又懊恼又警醒:"我以为分布式锁就是 SET NX 抢一下、DEL 删一下这么简单,完全没想到'锁会过期而业务没完''会删了别人的锁'这两个要命的细节。"这个坑最隐蔽的地方在于:偶发——只在"业务执行时间恰好超过锁 TTL"或"恰好有并发来抢过期的锁"时才触发,平时(业务很快、并发不高)完全正常;而且"加了锁"给了你强烈的安全错觉,让你根本不会怀疑锁本身有问题下面就来拆解,分布式锁该怎么正确实现。

第一件事:搞懂分布式锁的几个关键问题

我顺着这次事故,把分布式锁要正确处理的几个关键问题彻底理清了。

分布式锁要正确处理哪些关键问题?

【核心: 分布式锁要解决 ①防死锁(设过期) ②持锁超时(过期但业务没完→续期) ③只释放自己的锁(校验owner) ④原子性; 别只SET NX + DEL】

1. 为什么要分布式锁:
   - 多个进程/实例并发访问同一共享资源(临界区), 需要"同一时刻只有一个能进";
   - 单机锁(synchronized/Lock)只在一个进程内有效, 多实例下无效 → 要用分布式锁(Redis/ZK等)。

2. 关键问题①: 必须设过期时间(防死锁)
   - 若持锁进程崩了/卡死, 锁不释放 → 别人永远抢不到 → 死锁;
   - 所以要给锁设过期时间(EX), 即使持锁者挂了, 锁也会自动释放。

3. 关键问题②: 过期时间 vs 业务时长的矛盾(持锁超时)
   - 过期时间设短了: 业务没跑完锁就过期, 别人抢到 → 多进程同时进临界区(本文漏洞一);
   - 过期时间设长了: 持锁者崩了, 别人要等很久才能抢到 → 可用性差;
   - 矛盾的解法: "看门狗"自动续期——持锁期间后台定时给锁续期, 业务没完锁就不过期;
     业务完成或进程崩了(续期停止), 锁才到期释放 → 兼顾"不误释放"和"防死锁"。

4. 关键问题③: 只能释放自己的锁(防误删)
   - 释放时直接DEL → 可能删了别人的锁(本文漏洞二);
   - 解法: 加锁时value设一个【唯一标识(如UUID)】; 释放时先check"锁的value是不是我的", 是才删;
   - 且"check+del"必须【原子】(用Lua脚本), 否则check和del之间锁又可能过期被别人拿到。

5. 关键问题④: 原子性
   - 抢锁(SET NX EX)要原子(一条命令同时设值和过期, 别分两步);
   - 释放(校验owner + del)要原子(Lua脚本)。

6. 实践: 别自己造轮子, 用成熟实现
   - Redis: 用 Redisson(封装好了看门狗续期、唯一value、Lua原子释放等);
   - 也了解Redlock的争议(多节点, 但有争议, 一般单实例Redisson够多数场景);
   - 强一致要求高: 考虑ZooKeeper/etcd(基于一致性协议)。

一句话: 分布式锁要正确处理防死锁(设过期)、持锁超时(看门狗续期)、只释放自己的锁(唯一value+Lua原子校验删)、
   原子性; 别只"SET NX抢+DEL释放"; 优先用Redisson等成熟实现, 别自己造有坑的轮子。

这套认知,是整个坑的根。为什么要分布式锁:多进程/实例并发访问同一共享资源,单机锁多实例下无效,要用分布式锁。关键问题①必须设过期(防死锁):持锁进程崩了锁不释放=死锁,设过期即使持锁者挂了锁也自动释放。②过期时间 vs 业务时长的矛盾(持锁超时):设短了业务没完锁就过期、别人抢到(漏洞一);设长了持锁者崩了别人等很久;解法是"看门狗"自动续期(持锁期间后台续期、业务没完锁不过期,完成或崩了才释放)。③只能释放自己的锁(防误删):直接 DEL 可能删别人的锁(漏洞二);加锁 value 设唯一标识(UUID)、释放时先校验是自己的才删,且 check+del 必须用 Lua 原子④原子性:抢锁(SET NX EX 一条命令)、释放(Lua)都要原子。实践:别造轮子,用 Redisson(封装好看门狗续期、唯一 value、Lua 原子释放),强一致用 ZK/etcd。一句话:分布式锁要正确处理防死锁(设过期)、持锁超时(看门狗续期)、只释放自己的锁(唯一 value+Lua 原子校验删)、原子性;别只"SET NX 抢+DEL 释放";优先用 Redisson 等成熟实现,别自己造有坑的轮子。

第二件事:正解——唯一 value + Lua 原子释放 + 看门狗续期(或用 Redisson)

搞懂了原理,正解就清晰了:加锁带唯一 value、释放用 Lua 原子校验所有权再删、用看门狗自动续期解决持锁超时;最省心的是直接用 Redisson

// ====== 正解一: 唯一value + Lua原子释放(手写最小正确版) ======
String lockValue = UUID.randomUUID().toString();   // ★ 每次加锁用唯一标识

// 抢锁: SET NX EX 原子地设值+过期(value是自己的唯一标识)
boolean locked = redis.set("lock_key", lockValue, "NX", "EX", 30);
if (!locked) return;
try {
    criticalSection();
} finally {
    // ★ 释放: 用Lua脚本原子地"校验value是自己的才删", 防止删了别人的锁
    String lua =
        "if redis.call('get', KEYS[1]) == ARGV[1] then " +
        "  return redis.call('del', KEYS[1]) " +
        "else return 0 end";
    redis.eval(lua, List.of("lock_key"), List.of(lockValue));
    // → 只有锁还是我的(value匹配)才删; 若已过期被别人拿到(value变了), 不删 → 不会误删别人的锁。
}
// ====== 正解二: 用 Redisson(推荐, 自带看门狗续期+唯一value+Lua释放) ======
RLock lock = redisson.getLock("lock_key");
lock.lock();          // 加锁; Redisson默认开启"看门狗": 持锁期间后台每隔一段自动续期, 业务没完锁不过期
try {
    criticalSection();   // 即使业务跑很久, 看门狗一直续期, 锁不会中途过期
} finally {
    lock.unlock();    // 释放(内部已校验是自己的锁、原子操作)
}
// → Redisson把看门狗续期、唯一标识、Lua原子释放都封装好了, 解决了本文的两个漏洞, 省心可靠。
# ====== 实现要点 ======
# 1. 加锁原子: SET key value NX EX ttl 一条命令(别先SET再EXPIRE分两步, 中间崩了又死锁);
# 2. 唯一value: 每次加锁用UUID等唯一标识, 用来证明"这把锁是我的";
# 3. 释放原子+校验: 用Lua脚本"get校验是自己的 then del", 别用裸DEL(会删别人的);
# 4. 持锁超时: 用看门狗自动续期(Redisson默认), 让锁在"业务执行期间不过期、业务完/进程崩才释放";
#    若不用看门狗: 把ttl设得足够长(>业务最大耗时)并监控, 但不如续期优雅;
# 5. 优先用成熟库: Redisson(Redis)、curator(ZooKeeper); 别自己造轮子(细节多、易错);
# 6. 想清一致性要求: Redis分布式锁在主从切换等极端情况有丢锁风险(Redlock有争议);
#    对"绝对不能两个同时进"的强一致场景, 考虑ZK/etcd, 或在业务层加幂等/校验兜底。

# ====== 一个兜底思想 ======
# - 分布式锁很难做到100%可靠(分布式系统的固有难题); 关键业务别只依赖锁, 还要在业务层
#   加"幂等/唯一约束/状态机校验"等兜底(就算锁偶尔失效, 业务层也能挡住重复/并发的危害)。

# 核心: 分布式锁加锁带唯一value+原子设过期、释放用Lua校验所有权再删、用看门狗续期解决持锁超时;
#   优先用Redisson等成熟实现; 关键业务别只靠锁, 业务层再加幂等/校验兜底。

修复的核心,是"唯一 value + Lua 原子释放 + 看门狗续期,或直接用 Redisson"正解一:唯一 value + Lua 原子释放(手写最小正确版)——加锁 value 用 UUID、释放用 Lua"校验 value 是自己的才删",只有锁还是我的才删、不会误删别人的正解二:用 Redisson(推荐)——lock.lock() 自带看门狗(持锁期间后台续期、业务没完锁不过期)、唯一标识、Lua 原子释放,把两个漏洞都封装解决了实现要点:加锁原子(SET NX EX 一条)、唯一 value、释放原子+校验(Lua)、持锁超时用看门狗续期、优先用成熟库、想清一致性要求(Redis 锁有丢锁风险、Redlock 有争议、强一致用 ZK/etcd)兜底思想:分布式锁很难 100% 可靠,关键业务别只依赖锁,业务层再加幂等/唯一约束/状态机校验兜底归根结底:分布式锁加锁带唯一 value+原子设过期、释放用 Lua 校验所有权再删、用看门狗续期解决持锁超时;优先用 Redisson 等成熟实现;关键业务别只靠锁,业务层再加幂等/校验兜底。

第三件事:分布式系统协调中其他常见的坑

排查后我把分布式锁、分布式协调相关的其他坑也系统梳理了一遍。

分布式系统协调的其他常见坑

# 1. 分布式锁实现缺陷(本文): 锁过期没续期/误删别人锁。→ 看门狗+唯一value+Lua释放。

# 2. 锁没设过期: 持锁进程崩了, 死锁。→ 必设过期(配合续期)。

# 3. 只依赖锁不做幂等: 锁偶尔失效就出事。→ 业务层加幂等/唯一约束兜底。

# 4. 锁粒度太粗: 锁了过大范围, 并发全卡住。→ 锁到最小必要的资源(如按ID锁)。

# 5. 分布式事务想用2PC强一致: 复杂、性能差、协调者单点。→ 多数用最终一致(消息/SAGA)+幂等。

# 6. 时钟不同步: 依赖各节点本地时间做判断/排序出错。→ 别依赖墙上时钟, 用逻辑时钟/中心化时间。

# 7. 脑裂: 网络分区下多个节点都以为自己是主。→ 基于多数派(quorum)的选主。

# 8. 重复消息/乱序(MQ): 消费者要幂等、要能处理乱序。→ 幂等消费+必要时排序。

# 共同根源: 分布式系统里, "多个独立节点要对某件事达成一致协调", 而它们之间隔着"不可靠的网络、各自的故障、
#   没有全局时钟"——这使得很多单机下简单的事(加把锁、保证只执行一次)在分布式下变得极其困难;
#   任何"想当然地认为分布式协调和单机一样简单"的做法, 都会在网络分区/节点故障/超时等情况下露馅。

# 核心: 分布式协调(锁/事务/选主/一致性)是难题, 别用单机直觉简单处理; 用成熟的中间件和算法、
#   设过期+续期、做幂等兜底、基于多数派、别依赖时钟; 并接受"分布式锁等不是100%可靠"而在业务层留后手。

排查让我把分布式协调的其他坑也梳理清了。一、分布式锁实现缺陷(本文)。二、锁没设过期死锁三、只依赖锁不做幂等四、锁粒度太粗五、分布式事务想用 2PC 强一致六、时钟不同步七、脑裂八、重复消息/乱序它们的共同根源是:分布式系统里"多个独立节点要对某件事达成一致协调",而它们之间隔着不可靠的网络、各自的故障、没有全局时钟——这使得很多单机下简单的事在分布式下变得极其困难;任何"想当然认为分布式协调和单机一样简单"的做法,都会在网络分区/节点故障/超时等情况下露馅核心是:分布式协调(锁/事务/选主/一致性)是难题,别用单机直觉简单处理;用成熟的中间件和算法、设过期+续期、做幂等兜底、基于多数派、别依赖时钟;并接受"分布式锁等不是 100% 可靠"而在业务层留后手下面这张图,是这次分布式锁坑的成因与解法:

第四件事:错误锁 vs 正确锁对比表

这次踩坑后,我把"有缺陷的分布式锁"和"正确的分布式锁"对比成一张表。

维度 有缺陷的锁(本文) 正确的锁
过期时间 固定 EX, 业务超时就过期 看门狗续期, 业务期间不过期
锁的 value 固定值(如 "1") 唯一标识(UUID)
释放 直接 DEL(删谁都行) Lua 校验是自己的才删
持锁超时后果 多进程同时进临界区 不会(续期保住)
误删风险 会删别人的锁 不会(校验所有权)
可靠性 偶发崩坏 可靠(仍非100%)

这张表把两种锁钉清了。核心是:那个错误的锁,"正常路径"上看起来完全没问题(抢到锁、干活、释放),它的 bug 全藏在"异常/边界路径"里——业务超时、锁过期、并发抢到过期锁、删了别人的锁;而"正确的锁"和"错误的锁"的差距,恰恰就在于是否认真处理了这些"不那么常见、但一定会发生"的边界情况它给我的最大启发是:区分"玩具实现"和"生产级实现"的,往往不是"正常情况能不能跑"(两者都能),而是"对'异常、边界、并发、故障'这些情况的处理是否周全"——"happy path(顺利路径)谁都会写, 真正的功力在 unhappy path";那些被忽略的边界(超时、并发、部分失败、对方挂了),正是 bug 和事故的温床这给了我一种写关键代码时的清醒:实现任何"关键的、要可靠的"机制(锁、事务、状态机、协议)时,不能满足于"正常流程跑通了",而要专门、系统地把"异常和边界路径"列出来逐个考量——"如果超时了?如果对方挂了?如果并发来了?如果中途失败了?如果重复了?";"把功力下在 unhappy path、周全处理异常与边界",是写出生产级可靠代码、而非玩具代码的关键认清玩具与生产级的差距在异常边界路径、把功力下在 unhappy path——是这个坑带给我的认知。

第五件事:这次事故暴露的"看似简单的东西其实很难"

这次让我反思更深一层:"加把锁"在单机里是件小事,在分布式下却暗藏这么多陷阱。我把"单机锁"和"分布式锁"对比成表。

维度 单机锁(synchronized/Lock) 分布式锁
范围 一个进程内 跨进程/跨机器
持锁者崩了 JVM 自动释放 要靠过期(否则死锁)
过期 vs 业务时长 无此问题 核心难题(要续期)
释放 简单可靠 要防误删(校验所有权)
可靠性 语言保证 受网络/故障影响, 难100%
本质 简单 是个分布式共识难题

这张表道出了一个认知落差。核心是:"加一把锁"这件事,在单机里简单到我们从不思考(synchronized 一写,JVM 全包了);可一旦搬到分布式环境,它就暴露出底层是一个'多个节点在不可靠网络上对'谁持有锁'达成共识'的难题——过期、续期、所有权、网络分区,每一个都是坑;我栽跟头,正是因为我用"单机锁那么简单"的心态,去对待"分布式锁这个难题"它给我的深刻启发是:很多概念"名字一样、单机/小规模下简单",但在分布式/大规模/高可靠的语境下,会变成一个完全不同量级的难题——"锁、事务、计数、唯一、缓存、调用一个函数",在分布式下都比单机难一个数量级;"用'简单场景的简单认知'去对待'复杂场景下的同名问题'",会严重低估它的难度、做出脆弱的实现这给了我一种面对"看似简单"问题的敬畏:当我要在一个"更复杂的环境(分布式/高并发/高可靠)"里实现一个"名字听起来很简单"的功能时,要警惕"它在简单环境里的简单"给我的轻敌,主动去问"在这个复杂环境里, 它真的还简单吗?它隐藏了哪些单机下没有的难题?有没有成熟的方案别自己造?";"对'看似简单却在复杂环境下变难'的问题保持敬畏、借助成熟方案而非轻率自造",是避免在难题上栽跟头的关键认清看似简单的东西在分布式下是难题、对复杂环境下的同名问题保持敬畏——是这个分布式锁坑带给我的工程态度。

第六件事:要用分布式锁时,我现在的自检习惯

现在每当我要用分布式锁,我都会先按这张图问自己:

这张图的精髓,是"优先用成熟库,手写要带唯一 value+Lua 释放+续期,关键业务再加兜底"能用库用 Redisson、手写唯一 value+Lua 释放+看门狗续期、关键业务业务层加幂等兜底这套习惯,让我从"SET NX 抢 DEL 释放就完事"变成了"用成熟库、处理好续期和所有权、再加兜底"——核心始终是:分布式锁优先用 Redisson 等成熟实现,手写要带唯一 value、Lua 原子校验所有权释放、看门狗续期解决持锁超时,关键业务别只靠锁、业务层再加幂等校验兜底。

我立下的几条规矩

这场"加了锁还并发、还删了别人的锁"的事故,换来了我用分布式锁时,刻进骨子里的几条铁律:

  1. 分布式锁不是"SET NX 抢 + DEL 释放"这么简单。要处理超时、所有权、原子性。
  2. 锁必须设过期时间(防持锁者崩了死锁)。但要解决"业务超时锁却过期"的矛盾。
  3. 用看门狗自动续期:持锁期间续期,业务没完锁不过期,完成/崩了才释放。
  4. 加锁 value 用唯一标识(UUID),释放时用 Lua 校验是自己的才删。防误删别人的锁。
  5. 抢锁、释放都要原子(SET NX EX 一条命令;校验+删用 Lua)。
  6. 优先用 Redisson 等成熟实现,别自己造有坑的轮子。
  7. 分布式锁难 100% 可靠,关键业务在业务层加幂等/唯一约束兜底。

写在最后

回头看,这场由"一个看似简单的分布式锁"引发的、临界区失守的事故,真正教给我的,远不止"用 Redisson、Lua 释放"这几个技巧。它让我对"一个'保护机制', 若它自身的实现有漏洞, 那么它给你的'安全感'就是假的、甚至比没有它更危险——因为你会仗着这份虚假的安全感, 放松了本该有的警惕",有了一次刻骨的体会。我栽跟头,最深的一层,是因为"我加了锁"这个动作,给了我一种强烈的、却是虚假的安全感——我以为"有锁保护了, 临界区就一定是安全的、互斥的",于是我对临界区里可能的并发问题, 彻底放松了警惕,也没在业务层做任何兜底;可那把锁自身是有漏洞的(会过期、会误删),它并没有真正提供它"看起来"提供的保护;于是当锁失效时,既没有锁的真实保护、也没有我因信任锁而省掉的业务层防护——两头落空,问题就这么发生了这让我领悟到一个关于"保护机制与虚假安全感"的深刻认知:一个"不可靠的保护机制",其危害可能超过"没有保护"——因为"没有保护"时你会小心翼翼、处处设防;而"有一个看起来可靠的保护"时,你会信任它、依赖它、并因此卸下其他防备;一旦这个保护在关键时刻失效,你就处在"毫无防备"的最脆弱状态;"安全带没系好"比"知道没安全带而小心开车"更危险这给了我一种对待"保护机制"的根本审慎:当我依赖一个"保护/保障机制"(锁、事务、校验、备份、监控、容灾)时,要先严格地确认"它本身是不是真的可靠、它真的提供了我以为的保护吗?",而不要因为"有了它"就盲目地放松警惕——对关键的东西, 既要让保护机制尽量可靠, 也要保留'万一它失效'的兜底(纵深防御);"不被保护机制带来的安全感麻痹、确认其真实可靠性并留好兜底",是避免'因虚假安全感而双重失守'的关键意识认清不可靠的保护比没有保护更危险、别被安全感麻痹要确认其可靠性并留兜底——这,是我用一次分布式锁失守的事故,换来的、关于分布式系统、也关于如何清醒地依赖保护机制的、最朴素也最深刻的领悟。如果这篇复盘,能让你下次用分布式锁时,用上 Redisson、处理好续期和所有权、并在业务层留个兜底,那我对着那"加了锁还崩坏"的数据排查的这段时间,就值了。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

我们的 AI 功能上线第一个月,大模型 API 账单直接爆了十几倍,我一查才发现每个请求都在拿最贵的模型、塞着超长 prompt、重复算同样的东西的深度复盘

2026-6-2 21:39:29

技术教程

我那些频繁创建又销毁的对象,订阅了一个单例的事件却忘了退订,结果它们一个都没被回收、内存一路涨到 OOM:一次 C# 事件订阅未取消导致内存泄漏的深度复盘

2026-6-2 21:51:01

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索