GPU与CPU内存管理差异解析:从设计原理到实战避坑指南
1. 从一次诡异的“内存泄漏”排查说起去年我们团队在将一个核心的推理服务从CPU迁移到GPU时遇到了一件怪事。服务在CPU上跑得好好的内存使用稳定一到GPU上没过多久就触发了OOMOut of Memory错误进程被系统杀死。第一反应当然是查代码用nvidia-smi看GPU显存确实在缓慢增长直到爆掉。我们动用了torch.cuda.memory_allocated()、memory_reserved()甚至祭出了memory_snapshot()来抓取详细的内存分配记录一番折腾后发现问题出在一个我们以为“人畜无害”的Python列表上。这个列表里存放了一些中间张量的引用在CPU模式下这些张量占用的系统内存会被Python的垃圾回收机制GC正常释放。但到了GPU上即便Python层面的对象被GC回收了其对应的显存却没有被及时释放回CUDA的内存池导致显存“只进不出”。最终我们不得不手动调用torch.cuda.empty_cache()并重构了这部分缓存逻辑才解决了问题。这次经历让我深刻意识到GPU的内存管理GPU Memory Management, GMM和CPU的内存管理CPU Memory Management, CMM虽然名字里都有“内存管理”但它们在设计哲学、实现机制和开发者需要关注的细节上几乎是两个平行的世界。很多在CMM领域被视为常识的规则在GMM里可能完全不适用甚至会成为性能陷阱。理解这个“平行宇宙”对于进行高性能计算、深度学习模型训练和推理的开发者来说不是选修课而是必修课。2. 设计根源为何GPU内存管理自成一体要理解两者的差异必须回到它们服务的根本目标上。CPU MM以Linux内核为例的核心设计目标是通用性、公平性和安全性。它要服务于从文本编辑器到数据库的各种各样、行为不可预测的进程确保它们彼此隔离不会互相踩踏内存并公平地分享物理内存资源。其管理的内存是系统的主内存DRAM通过复杂的页表、TLB、缺页中断、换入换出Swap等机制为上层应用提供了一个统一的、巨大的虚拟地址空间。而GPU MM以NVIDIA CUDA为例的设计目标则极为专一最大化数据吞吐量最小化访存延迟以服务于大规模并行计算。GPU的显存VRAM带宽通常是系统内存的数倍甚至十倍以上如HBM2e显存带宽可达1-2TB/s而DDR5内存带宽在100GB/s量级但容量更小且与CPU系统内存物理分离。这个根本差异导致了GMM的一系列独特设计内存层次结构更复杂GPU不仅有全局显存还有共享内存Shared Memory、常量内存Constant Memory、纹理内存Texture Memory和寄存器Register。每一层都有其特定的访问特性、速度和用途。CUDA编程模型要求开发者显式地管理数据在这些层次间的移动和存放这与CPU上“内存就是内存”的抽象截然不同。分配/释放成本模型不同在CPU上malloc/free或new/delete的成本相对固定且较低。但在GPU上显存的分配cudaMalloc和释放cudaFree是非常昂贵的操作可能涉及与内核驱动程序的同步、页表的更新等。因此GMM普遍采用内存池Memory Pool技术。应用释放的显存并不立即交还给操作系统而是留在一个由CUDA运行时或深度学习框架如PyTorch、TensorFlow维护的内存池中以备后续分配重用。这就是为什么nvidia-smi看到的“已使用”显存在程序释放对象后可能不会立即下降的原因。缺乏操作系统级的“交换”机制系统内存不足时操作系统可以将不活跃的内存页交换Swap到硬盘上。但GPU显存没有等效的、通用的“显存交换”机制虽然有类似GPU Direct Storage的技术但非通用且需特定配置。一旦显存耗尽通常的结果就是分配失败cudaErrorMemoryAllocation或进程崩溃。这迫使开发者必须进行更精细、更主动的显存容量规划和管理。统一内存Unified Memory的“魔法”与代价为了简化编程CUDA引入了统一内存UM的概念通过cudaMallocManaged分配的内存可以被CPU和GPU共同访问数据迁移由驱动在后台自动完成。这看起来很美像是弥合了两个宇宙。但其背后是更复杂的页迁移机制Page Migration在发生页面错误Page Fault时数据在CPU和GPU内存间的迁移会带来不可预测的性能抖动。对于性能敏感的应用手动管理数据移动cudaMemcpy往往是更可靠的选择。简单来说CPU MM为你建造了一个坚固、通用但略显笨重的大厦你可以在里面随意隔间、装修而GPU MM则给了你一个结构精密、通道极速但面积有限的赛车维修站你需要精确地知道每个工具、每个零件该放在哪个特定位置并且移动它们本身就需要消耗时间。3. 实战困境开发者日常踩坑点解析理解了设计差异就能解释开发中那些反直觉的现象了。以下是一些典型场景3.1 内存释放的“滞后性”与缓存陷阱正如开篇案例所示这是最常见的一坑。在PyTorch中当你将张量移到GPU.cuda()或使用torch.cuda.FloatTensor创建它时框架会从CUDA内存池中申请显存。当你将这个张量的Python引用置为None或者它离开作用域时Python的GC会回收这个Python对象但对应的显存块只是被标记为“可重用”并返还给PyTorch的CUDA内存池而不是立即释放给操作系统。import torch # 分配一块显存 x torch.randn(1000, 1000).cuda() # 删除引用 del x # 此时nvidia-smi或torch.cuda.memory_allocated()可能显示显存占用并未减少。 # 显存仍在PyTorch的内存池中。为什么这么设计因为反复向操作系统申请和释放显存代价太高。内存池将释放的块缓存起来下次分配相似大小的内存时可以直接从池中取出避免了昂贵的系统调用极大提升了分配速度。给开发者的启示不要频繁分配/释放小显存块这会导致内存池碎片化并可能因为池化机制而长期占用显存。尽量复用张量或使用视图view操作。理解empty_cache()的作用与代价torch.cuda.empty_cache()会强制释放内存池中所有未使用的缓存块将其归还给操作系统。这是一个同步操作可能会引起性能波动。它是一剂“猛药”适用于需要为后续大块分配腾出最大连续空间的情况但不应该作为常规清理手段在循环中调用。监控工具要看全不要只看nvidia-smi的“Used”列。使用torch.cuda.memory_reserved()查看内存池当前总共占用了多少显存包括已分配和空闲缓存用memory_allocated()查看实际被张量占用的显存。两者的差值就是内存池中空闲的缓存。3.2 内存碎片化隐形的性能杀手内存碎片化在CPU和GPU上都是问题但在GPU上后果更严重。由于GPU内核启动需要连续的显存空间来存放输入、输出和中间数据如果显存被分割成许多小块即使总空闲空间足够也可能无法分配出一个连续的大块导致分配失败。GPU内存碎片化的成因更特殊不同生命周期的张量混合长期存在的模型参数张量大块、长生命周期和短期存在的中间激活张量小块、短生命周期交替分配释放极易在长期大块之间留下无法被利用的小空隙。内存池的最佳适配策略为了快速分配内存池在分配时可能采用“首次适配”或“最佳适配”策略这本身就会产生外部碎片。应对策略使用torch.cuda.memory_stats()诊断关注“allocated_bytes.all.current”和“reserved_bytes.all.current”并留意“active_bytes.all.current”当前活跃分配与总保留字节数的比例。如果保留了很多但活跃的很少可能碎片化严重。优化张量生命周期尽量让大小相似、生命周期相近的张量一起分配和释放。例如在训练循环中可以考虑将一些小的中间变量合并到一个大的缓冲区中。重启进程对于长期运行的服务如果观察到显存可用空间持续下降但实际分配不多重启进程是清除碎片最彻底的方法。一些框架如TensorFlow的tf.config.experimental.set_memory_growth可以避免一开始就占用所有显存有助于缓解碎片。3.3 统一内存UM的“甜蜜陷阱”统一内存让代码写起来非常简洁似乎不用再操心cudaMemcpy。但对于高性能场景它可能是陷阱。// 方便但可能有性能隐患 cudaMallocManaged(data, size); kernel...(data); // 首次访问会触发页错误和数据迁移问题在于按需迁移的延迟数据在CPU和GPU间迁移发生在GPU内核首次访问该内存页时GPU Page Fault。这个延迟是难以预测的并且会阻塞所有该GPU上的线程对需要稳定低延迟的推理服务是致命的。超额订阅Oversubscription风险UM允许分配的总量超过GPU显存容量依赖系统内存作为后备。当GPU频繁访问超出其物理显存的数据时会引发大量的数据迁移Thrashing性能急剧下降。最佳实践预取Prefetching如果使用UM应在内核启动前使用cudaMemPrefetchAsync将数据明确预取到GPU内存消除按需迁移的延迟。对于已知的、稳定的数据流坚持使用显式拷贝cudaMemcpyAsync。虽然代码多几行但性能可预测是生产环境的首选。将UM视为优化手段而非默认选择先使用显式拷贝实现功能在性能剖析Profiling后如果发现数据迁移是瓶颈再考虑是否有选择地使用UM并进行精细的预取优化。3.4 多进程/多GPU环境下的复杂交互在单进程单GPU场景下内存管理已不简单。扩展到多进程如Python多进程或多GPU数据并行、模型并行时复杂度指数级上升。CUDA上下文与进程绑定每个使用CUDA的进程都会创建一个CUDA上下文Context它包含了该进程的GPU状态、内存分配等。一个GPU设备可以被多个进程的上下文共享。如果某个进程崩溃后没有正确清理上下文其占用的显存可能不会被释放导致“显存泄漏”。这就是为什么有时候重启单个进程无法释放显存必须重启所有相关进程甚至整个服务器。Peer-to-Peer (P2P) 访问与NVLink在多GPU系统中GPU之间可以直接访问彼此的显存P2P绕过CPU。这需要显式启用并且受硬件拓扑如是否通过NVLink高速互联影响。P2P访问的内存管理分配、释放、一致性比单GPU更复杂。框架级别的多GPU并行像PyTorch的DistributedDataParallel(DDP)每个进程通常对应一个GPU。框架会负责将模型复制到每个GPU并在反向传播后同步梯度。这里的内存开销不仅仅是模型参数还包括每个GPU上独立的优化器状态、梯度缓冲区以及通信所需的缓冲区。计算总显存需求时必须是单卡需求 * GPU数量并额外考虑通信开销。注意在容器化如Docker环境中运行GPU应用时需要确保容器内的CUDA驱动版本与宿主机驱动兼容并且通过--gpus参数正确将GPU设备挂载到容器内。错误配置可能导致容器内无法看到GPU或出现奇怪的显存错误。4. 工具链如何观测和调试GPU内存宇宙在CPU世界我们有top,htop,vmstat,Valgrind等利器。在GPU宇宙我们也有一套专属的工具链。4.1 基础监控命令行工具nvidia-smi最常用的实时监控工具。关键指标Memory-Usage: 当前GPU上所有上下文使用的显存总量。注意这包含了内存池中的缓存。GPU-Util: GPU计算单元利用率。Volatile GPU-Util: 更准确的计算活动指示。nvidia-smi -l 1可以每秒刷新一次观察动态变化。nvtop类似于htop的GPU监控工具提供更直观的实时视图包括每个进程的显存占用。4.2 框架内置工具PyTorchimport torch # 快照式信息 print(torch.cuda.memory_allocated()) # 当前张量占用的显存 print(torch.cuda.memory_reserved()) # 内存池当前保留的总显存 print(torch.cuda.max_memory_allocated()) # 自程序开始以来分配峰值 # 详细统计 print(torch.cuda.memory_stats()) # 更详细的内存事件快照用于调试 snapshot torch.cuda.memory_snapshot() # 清理缓存谨慎使用 torch.cuda.empty_cache()TensorFlow可以通过tf.config.experimental.get_memory_info(GPU:0)获取信息并设置内存增长策略。4.3 高级剖析与调试Nsight Systems Nsight ComputeNVIDIA官方性能剖析神器。Nsight Systems系统级性能分析可以看到CPU和GPU的时间线清晰地显示内核执行、内存拷贝H2D, D2H、CUDA API调用、显存分配/释放事件。它能帮你定位是计算慢还是内存拷贝慢以及显存分配是否过于频繁。Nsight Compute内核级性能分析深入每个CUDA内核分析其寄存器使用、共享内存使用、全局内存访问模式、带宽利用率等。对于优化内核级别的显存访问合并访问、减少bank冲突至关重要。CUDA-MEMCHECK类似于Valgrind用于检测内存访问错误越界、未初始化访问等。命令如compute-sanitizer --tool memcheck ./your_app。cuda-gdbGPU版的GDB调试器可以设置断点、检查变量包括设备变量、单步执行内核代码。一个典型的排查流程是先用nvidia-smi或nvtop观察显存增长趋势和哪个进程可疑然后用PyTorch/TensorFlow的内存接口在代码关键点插入日志定位增长发生在哪个操作之后最后用Nsight Systems进行时间线分析看是否伴随异常的内存拷贝或内核执行模式。5. 优化策略在两个宇宙间架起高效桥梁掌握了问题和工具最终目的是为了优化。以下是跨越CPU和GPU内存宇宙的一些核心策略5.1 计算与通信的重叠这是GPU编程的金科玉律。利用CUDA流Stream和异步操作让GPU在执行计算内核的同时通过DMA引擎在后台进行下一次计算所需的数据传输CPU到GPU即H2D。# 伪代码示例 stream torch.cuda.Stream() with torch.cuda.stream(stream): # 在stream中异步拷贝数据到GPU data_gpu data_cpu.to(cuda, non_blockingTrue) # 在另一个流或默认流中执行其他计算... # 等待数据就绪后在stream中启动计算内核 result model(data_gpu)通过流水线化将数据传输的时间隐藏起来有效提升GPU利用率。5.2 激活重计算Gradient Checkpointing在训练非常深的神经网络时中间激活Activation会消耗大量显存用于保存以便反向传播时计算梯度。激活重计算技术选择性地不保存某些层的激活在反向传播需要时根据保存的较早的激活临时重新计算这些中间激活。这是一种经典的**“用计算换显存”** 的策略。PyTorch中可以通过torch.utils.checkpoint.checkpoint函数轻松实现。5.3 混合精度训练使用torch.cuda.amp自动混合精度模块。将模型权重、激活和梯度的一部分从FP32转换为FP16。FP16张量占用显存是FP32的一半因此可以大幅减少显存占用同时利用Tensor Core进行更快的计算。AMP会自动管理精度转换和梯度缩放在保持训练稳定性的前提下获得显存和速度的双重收益。5.4 模型切分与卸载当模型大到单卡放不下时模型并行Model Parallelism将模型的不同层放到不同的GPU上。例如前几层在GPU0中间几层在GPU1最后几层在GPU2。需要手动管理层间张量的跨设备移动。流水线并行Pipeline Parallelism将模型按层切分到多个GPU并将一个batch的数据进一步分成多个微批次Micro-batch。每个GPU处理一个微批次的不同阶段形成流水线提高设备利用率。FairScale、DeepSpeed等库提供了支持。ZeROZero Redundancy OptimizerDeepSpeed库中的核心技术。它将优化器状态、梯度和模型参数在数据并行的多个GPU间进行分区存储每个GPU只保存一部分从而将显存占用从O(model_size * num_gpus)降低到O(model_size / num_gpus)实现了几乎线性的显存扩展。5.5 内存格式与访问模式优化这属于更底层的优化但对于极致性能至关重要合并访问Coalesced Access确保GPU的线程束Warp中的线程访问全局显存时地址是连续的这样多个内存请求可以被合并成一次大的事务极大提升带宽利用率。这通常意味着要优化数据在内存中的布局例如使用NHWC格式可能在某些情况下比NCHW更适合CUDA。使用共享内存Shared Memory共享内存是GPU上的片上高速缓存速度比全局显存快一个数量级。将全局显存中需要被一个线程块Block内多次访问的数据先加载到共享内存中可以显著减少对全局显存的访问延迟和带宽压力。避免Bank冲突共享内存被组织成多个Bank。如果同一个线程束内的多个线程同时访问同一个Bank的不同地址就会发生Bank冲突导致访问串行化。设计数据结构和访问模式以避免Bank冲突是优化共享内存使用的关键。GPU内存管理这个“平行宇宙”的规则虽然独特甚至严苛但一旦掌握就能释放出硬件的巨大潜力。它要求开发者从“内存自动管理”的舒适区走出来以更主动、更精细的视角去审视数据流动和生命周期。这种思维模式的转变正是高性能计算和深度学习开发的核心挑战与乐趣所在。每一次对显存碎片的清理、对数据流的重叠、对精度的巧妙混合都是在这两个宇宙间搭建起更高效桥梁的努力。

相关新闻

PID控制原理深度解析:从数学公式到工程实践

PID控制原理深度解析:从数学公式到工程实践

1. 项目概述:为什么PID是控制领域的“万金油”?如果你接触过自动化、机器人、无人机,甚至是家里的恒温热水器,那么“PID”这个词你一定不陌生。它就像一个无处不在的幽灵,默默地调节着电机的转速、无人机的姿态、烤箱的…

2026/8/13 3:59:53 阅读更多 →
TokenWorks:企业级大模型推理服务的成本、性能与稳定性优化实践

TokenWorks:企业级大模型推理服务的成本、性能与稳定性优化实践

1. 从“算力焦虑”到“Token焦虑”:企业推理服务的新挑战最近和几个做AI应用落地的朋友聊天,话题已经从半年前的“GPU卡怎么这么贵”和“模型怎么部署”,悄然转向了“这个月API调用费又超了”和“为什么响应这么慢”。这背后反映了一个深刻的…

2026/8/13 3:59:53 阅读更多 →
基于Docker与Playwright的Web自动化测试CI/CD实践

基于Docker与Playwright的Web自动化测试CI/CD实践

1. 项目概述与核心价值最近在团队里搞CI/CD流程优化,发现一个挺普遍的问题:Web自动化测试的环境依赖太“娇气”了。一个项目,A同事的机器上跑得好好的,B同事一拉下来就报各种Chrome版本不匹配、Node.js依赖缺失的错。更别提用Jenk…

2026/8/13 3:59:53 阅读更多 →

最新新闻

SUBTERRA音源深度解析:从工业采样到黑暗氛围音效实战

SUBTERRA音源深度解析:从工业采样到黑暗氛围音效实战

最近在探索工业音乐与暗黑氛围的创作时,常常感到市面上的许多音源要么过于“干净”缺乏冲击力,要么合成感太强缺少真实的工业质感。为了在影视配乐、游戏音效或实验电子乐中营造那种令人窒息的压迫感和地下空间的回响,一套高质量、风格纯粹的…

2026/8/13 4:37:23 阅读更多 →
微信小程序学生签到系统:三重验证与SSM架构实践

微信小程序学生签到系统:三重验证与SSM架构实践

1. 项目概述:微信小程序学生签到系统的核心价值这个基于微信小程序的学生签到系统,本质上解决了传统纸质签到或固定设备签到的三大痛点:硬件依赖性强、数据统计滞后、身份核验困难。我在高校信息化项目实践中发现,90%的课堂签到异…

2026/8/13 4:37:23 阅读更多 →
个人成长系统构建:从自我认知到价值实现的实践指南

个人成长系统构建:从自我认知到价值实现的实践指南

1. 项目概述:一场关于自我认知与实现的深度对话“DalinX 自述:从认识自己到成为自己-黎明前的第七杯咖啡”,这个标题本身就充满了叙事感和隐喻。它不像一个传统的技术项目,更像是一段个人成长旅程的记录,或者说&#x…

2026/8/13 4:37:23 阅读更多 →
AI编程工具与程序员角色的历史性转变

AI编程工具与程序员角色的历史性转变

1. 从“写代码”到“指挥代码”:程序员角色的历史性转变十年前的程序员日常是这样的:早上打开IDE,对着需求文档开始敲键盘,调试到深夜只为解决一个数组越界问题。而今天,GitHub Copilot能自动补全整段代码,…

2026/8/13 4:37:23 阅读更多 →
UBTech U1人形机器人:从任务执行到情感陪伴的技术演进与挑战

UBTech U1人形机器人:从任务执行到情感陪伴的技术演进与挑战

1. 项目概述:从“听懂”到“陪伴”的跨越最近,UBTech(优必选)的U1人形机器人成了圈内一个挺有意思的讨论点。大家关注的焦点,已经从它能不能精准地执行“去拿个水杯”这类指令,转向了它能不能在你下班回家时…

2026/8/13 4:37:23 阅读更多 →
MOS管泄漏电流全解析:从I_DSS到GIDL,硬件工程师必知的功耗陷阱

MOS管泄漏电流全解析:从I_DSS到GIDL,硬件工程师必知的功耗陷阱

1. 项目概述:从“漏电”说起,一个被忽视的功耗黑洞 做硬件设计,尤其是涉及电池供电、低功耗场景的工程师,对“功耗”这个词都异常敏感。我们花大量精力去优化主控的休眠电流,去选择低静态电流的LDO,却常常忽…

2026/8/13 4:36:22 阅读更多 →

日新闻

Visual Studio新建项目解决方案为空:系统性排查与修复指南

Visual Studio新建项目解决方案为空:系统性排查与修复指南

1. 问题现象与本质剖析如果你是一位.NET开发者,或者正准备踏入这个领域,那么Visual Studio(后面简称VS)绝对是你绕不开的伙伴。但有时候,这个伙伴会跟你开一个不大不小的玩笑:你满怀期待地点击“创建新项目…

2026/8/13 0:00:09 阅读更多 →
长春建设厅网站:普通人买房办事必看的真实指南与避坑攻略

长春建设厅网站:普通人买房办事必看的真实指南与避坑攻略

说实话,每次提起“长春建设厅网站”这几个字,我心里都挺有感触的。不是因为它有多高大上,也不是因为那里藏着什么不可告人的秘密,恰恰相反,是因为它太“接地气”了,或者说,它是咱们普通人想要在这个城市好好生活、安稳买房时,必须得翻过的一座“数据山”。很多新朋友第…

2026/8/13 0:00:09 阅读更多 →
Windows家庭版远程桌面多用户破解完整指南:RDPWrap终极解决方案

Windows家庭版远程桌面多用户破解完整指南:RDPWrap终极解决方案

Windows家庭版远程桌面多用户破解完整指南:RDPWrap终极解决方案 【免费下载链接】rdpwrap.ini RDPWrap.ini for RDP Wrapper Library by StasM 项目地址: https://gitcode.com/GitHub_Trending/rd/rdpwrap.ini 你是否曾为Windows家庭版无法支持多用户远程桌面…

2026/8/13 0:00:09 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/13 2:38:34 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/12 1:11:09 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/12 1:11:08 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/11 17:09:45 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/12 1:11:10 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/11 17:09:45 阅读更多 →