Android智能指针RefBase/sp/wp底层原理与避坑指南
做Android系统开发这些年最常打交道的一套内存工具就是平台自带的智能指针RefBase、sp、wp。跟纯C项目里习惯性用std::shared_ptr不同Android在Framework、Binder、图形栈等大量native模块里都坚持用这套自研智能指针这背后有历史原因也有现实的性能考量。很多刚开始啃AOSP源码的同行会有一个共同疑问项目里明明可以用C11标准库为什么还要维护一套sp/wp这篇就把Android智能指针的使用方法、底层计数模型、常见坑点集中拆一遍适合准备啃Framework源码的开发者也适合已经在写native模块但被生命周期问题折磨过的人。这篇文章不会只讲API怎么调我会把“为什么这么设计”也讲清楚。比如强引用和弱引用为什么是两套计数、wp怎么安全地提升回sp、析构为什么一定要走sp而不是手动delete这些细节搞明白之后再去看系统源码会轻松很多。后面还会附上我实际调试中踩过的几个典型崩溃案例以及一套相对好用的排查思路。1. 先搞明白Android 自研智能指针想解决什么问题1.1 native层对象生命周期为什么这么难管Android系统里大量核心服务都是用C实现的。一个native对象可能被创建它的模块使用也可能被注册进某个回调接口再被另一个线程甚至另一个进程的Binder调用持有。这个过程中对象的创建点和释放点经常隔着十万八千里单纯靠“谁new谁delete”的约定很难不出事。举个最常见的场景一个图形缓冲区对象被生产者创建后要交给消费者异步使用。生产者线程已经把这个对象从自己的逻辑里移除但消费者线程还握着一份指针正准备做渲染。如果生产端提前把对象delete了消费端就会拿到一个悬空指针轻则读到垃圾数据重则直接崩溃在native层。这类问题在早期Android版本里是稳定性事故的主要来源之一。裸指针最大的问题在于它不携带任何所有权信息。没有人知道当前这个指针背后到底还有谁在引用这个对象。传统C项目解决这个问题靠的是定规矩比如“这个模块只管创建那个模块负责释放”但规矩在跨模块、跨线程、跨进程的复杂调用链里很容易被打破。于是智能指针成了必然选择它把“谁负责释放”这件最难的事交给编译器靠引用计数自动完成。1.2 为什么有标准库智能指针还不用C11之后标准库提供了shared_ptr和weak_ptr理论上能覆盖大部分场景。可Android在C11普及之前就已经建立了一套RefBase体系而且系统代码规模极其庞大迁移成本根本不是一个小工程。更重要的是Android这套智能指针有一些标准库替代不了的设计点。最典型的差异是引用计数的存储方式。shared_ptr的控制块是独立的堆上结构与对象本身分离而Android的sp要求在对象内部嵌入一套计数信息也就是对象必须继承RefBase。这样做的好处是对象和计数永远在一起缓存局部性好也方便系统在对象生命周期结束时做一些自动清理动作。Binder框架正是依赖这种设计来联动服务端对象的强弱引用状态。另外Android对“弱引用提升”的需求比普通应用强烈得多。Binder回调、观察者模式、跨进程代理绑定这些场景经常需要一个不增加引用计数的“观察位”等真正要用的时候再尝试提升为强引用。wp的存在就是为了满足这个需求而且提升时机、失败判定都做得很细。标准库weak_ptr当然也能做类似的事但在Android整个生态里把这套逻辑内建到RefBase里跟系统组件配合起来更顺畅。1.3 认识几个主角RefBase、sp、wp、LightRefBase简单梳理一下这套智能指针家族的关系。RefBase是所有需要被sp管理的对象的基类它内部维护了强弱两套引用计数。sp是强引用智能指针作用类似shared_ptrwp是弱引用智能指针作用类似weak_ptrLightRefBase是RefBase的轻量版本只有强引用计数没有弱引用能力适合那些生命周期非常简单、不想背弱引用包袱的对象。一个对象如果希望被Android智能指针体系管理通常要继承RefBase。sp持有对象时会自动增加强引用计数析构时自动减少wp持有对象时会增加弱引用计数但它不保证对象仍然活着想通过wp拿到可用的sp必须走promote流程。这套设计与标准库虽然表面上相似但底层行为有差异后面章节会详细拆解。实际源码里还会看到很多单独用sp 声明变量的情况比如Framework服务端的Binder对象、Surface、BufferQueue消费者等几乎都是这套体系。理解这几个基础类型之间的关系再看这些代码就不会一头雾水。2. 核心机制拆解sp、wp 的引用计数与 promote 提升2.1 RefBase内部强弱计数模型RefBase对象内部不是简单维护一个int而是维护了一个weakref_type内部对象。这个内部对象管理两个计数器mStrong是强引用计数mWeak是弱引用计数再加上一个生命周期策略标志mFlags。可以把这个内部对象想象成贴在对象身上的一个“控制面板”sp每持有一份就点亮一个强引用灯wp每持有一份就点亮一个弱引用灯。mFlags用于控制对象在什么条件下可以析构。默认情况是OBJECT_LIFETIME_STRONG意思是只要强引用计数降到0对象就立刻析构不管还有没有弱引用。另一种常用策略是OBJECT_LIFETIME_WEAK这种情况下强引用降为0时对象不急着销毁而是等弱引用计数也降为0再销毁。这个设计让对象可以在危险期被wp临时“赎”回来也就是promote成功这是标准库weak_ptr做不到的。生命周期策略一般在构造函数里调用extendObjectLifetime来设置。这个机制对解决一些特别复杂的异步场景很有用但也容易埋雷——如果对象长期处于弱引用被延迟析构的状态资源释放会比你预想的晚排查时不容易发现。所以在我看来非必要不要改默认策略保持和标准库行为一致反而省心。2.2 sp的incStrong与decStrong执行路径sp模板类内部只保存一个T* m_ptr。构造sp (new T())时sp会调用m_ptr-incStrong(this)把强引用计数加1析构时调用m_ptr-decStrong(this)把强引用计数减1。这一加一减的关系是所有引用计数逻辑的基础。decStrong内部会检查强引用计数减到0之后根据mFlags决定怎么处理。默认STRONG策略下会直接delete这个RefBase对象。由于RefBase的析构是virtual即便是通过基类指针触发delete最终也会正确调用到真实子类的析构函数。这也是为什么很多RefBase子类会把析构函数声明为protected外面不敢直接delete裸指针但sp内部的decStrong却可以通过基类虚析构把对象干净地清掉。sp还有一个容易被忽略的点拷贝赋值不是摧毁旧指针就完事。当sp从别的sp拷贝过来时要先对新的m_ptr做incStrong再对旧的m_ptr做decStrong顺序反了可能在新指针计数还没增加时就被另一个线程减到零销毁。实际Android实现里这部分会有对应的处理逻辑但作为使用者我们最好也养成“先加后减”的心智模型。sp没有裸指针那么灵活但正因为它把inc和dec都封装好了才能做到“只要sp还活着对象一定还活着”。用sp管理对象之后最忌讳的就是再手动调用delete那等于绕过了计数器直接摧毁所有权机制大概率引发双重释放。2.3 wp的promote提升到底做了什么wp内部不会直接调用incStrong而是通过createWeak获取并操作weakref_type。wp只增加弱引用计数不影响对象是否会被析构。要从wp安全拿回sp必须调用promote。promote内部会尝试执行attemptIncStrong——这名字已经说明态度只是“尝试”把强引用计数加上去不一定成功。attemptIncStrong会判断当前对象是否还有效。默认STRONG策略下如果强引用计数已经是0那说明对象已经析构promote失败返回空的sp如果强引用计数还大于0说明对象还活着就把强引用计数加1并返回一个有效的sp。在WEAK策略下即使强引用计数是0只要弱引用还控制着对象promote也可能成功等于把对象从“待销毁”状态重新拉回“存活”状态。所以wp.promote()返回的sp必须判空。很多新手把wp当普通shared_ptr用以为它持有的对象肯定还在结果promote返回空之后没有检查就直接调方法照样崩溃。记住一个原则wp是一个观察者不是所有者任何从观察者到所有者的转换都伴随着失败的可能。2.4 Android智能指针与标准库的对照shared_ptr和weak_ptr在绝大多数C工程里已经是标配Android这套体系也常被拿来跟标准库做对比。搞清楚它们的异同能帮你判断自己手里的项目到底适合用哪套。对比维度Android sp/wpstd::shared_ptr/weak_ptr计数存储位置内嵌在RefBase对象内部独立的堆上控制块对象是否必须继承基类必须继承RefBase任意类型都可以管理弱引用提升wp::promote()可能失败需要判空weak_ptr::lock()同样可能返回空生命周期策略支持延迟析构、弱引用复活标准行为强引用为0即析构线程安全引用计数原子更新对象数据需自行加锁控制块原子管理对象数据仍需自行加锁运行环境依赖AOSP源码环境依赖libutilsC标准库任意环境可用适用主流场景Framework、Binder、系统Native层NDK库、通用业务代码、算法模块从功能上看两套体系解决的问题高度重合。但Android这套与系统服务、Binder机制有天然耦合比如Binder相关类本身就继承自RefBase服务端常利用onLastStrongRef回调来做资源收尾。而标准库智能指针胜在通用和可移植不依赖任何Android内部库。两种工具不是替代关系更多是各就各位、各管一摊。3. 实操演示写一个基于 RefBase 的 native 模块3.1 RefBase子类的基本定义规范定义一个被智能指针管理的类第一件事就是继承RefBase。下面是一个典型的例子我会在主逻辑里展示怎么创建、传递、降级观察。注意析构函数我特意设为protected这是为了避免外部直接delete裸指针。#include utils/RefBase.h #include utils/StrongPointer.h #include utils/WeakPointer.h #include cstdio class Worker : public RefBase { public: Worker() { printf(Worker created\n); // 默认生命周期策略是OBJECT_LIFETIME_STRONG } void doWork() { printf(Worker is working, strong count %d\n, getStrongCount()); } protected: // 设置为protected防止外部直接delete virtual ~Worker() { printf(Worker destroyed\n); } private: int mJobId 0; };构造函数我这里保持public方便直接new出来交给sp析构保护起来让所有销毁动作统一从sp的decStrong路径走。getStrongCount()是RefBase提供的接口可用来观察当前强引用计数适合调试时打日志。incref和decref相关的调用都不用自己操心交给sp和wp就行。3.2 创建、拷贝与传参始终围绕sp操作最正确的创建方式是先裸new然后立刻交到sp变量里。spWorker worker new Worker(); worker-doWork();这一步的语义是对象刚诞生的那一刻所有权就交给sp了。从此时起不要再想着手动delete这个Worker指针也不要把裸指针存到某个成员变量里长期保管。后面如果想在另一个函数里使用同一个对象直接传递sp即可sp拷贝时引用计数会自动增加函数结束时自动减少。参数传递时如果不需要修改对象所有权可以用const spWorker传入避免无谓的拷贝计数开销如果函数需要异步持有这个对象再按值传递sp让它持有一份强引用直到任务完成。这个习惯跟shared_ptr几乎一致熟悉标准库的人很容易迁移。有一点需要特别提醒不要用一个裸指针去初始化两个sp。比如同一个原始指针一处交给sp1另一处又交给sp2两个sp都认为自己是唯一所有者引用计数会混乱。虽然两个sp各自递增递减不会立刻崩但一旦中间又混入原始指针delete问题就会瞬间爆发。3.3 wp弱引用的正确姿势缓存、回调、观察者弱引用最常见的用途是缓存和回调。A模块想记住B模块的对象但又不希望自己的持有导致B模块永远无法释放这时就该用wp而不是sp。下面的例子模拟了一个数据消费者持有生产者的弱引用每次要用的时候才promote。class Consumer : public RefBase { public: void setProducer(const spWorker producer) { mProducer producer; // wp从sp构造只增加弱引用 } void refresh() { spWorker locked mProducer.promote(); if (locked ! nullptr) { locked-doWork(); } else { printf(producer is already gone\n); } } private: wpWorker mProducer; };Consumer持有的是wp所以即使生产者被外界所有强引用释放Consumer也不会阻止它析构。refresh每次调用时都尝试promote成功说明生产者还活着可以安全执行任务失败则说明对象已销毁做一次降级处理比如重新获取生产者或者上报一个空状态。这里promote返回的空sp必须判断。我不止一次见过有同学拿到空sp直接解引用在release版本上出现极其隐蔽的native crash。另外wp本身也可以用来判断两个观察者是否指向同一个对象这在管理缓存表时很方便。3.4 与Binder、回调和跨模块对象打交道的常见要点在AOSP的Framework层Binder相关的核心类普遍继承自RefBase例如服务端的Binder服务类自身。服务对象被创建后通常用sp先持有一份保证在客户端仍持有binder引用时服务对象不会提前销毁。当服务端最后一个强引用被释放RefBase会回调onLastStrongRef这是做资源收尾的好位置。在跨模块传递对象时尽量不要暴露裸指针接口。对外接口定义成sp 入参或返回值内部一致使用智能指针管理。这样能保证所有使用者都走同一套引用计数规则。如果必须传递裸指针给某个系统接口出参时要格外小心调用方只把它当成“借用”不得擅自delete更不得在异步场景长期保存。回调场景也一样。如果某个回调对象可能晚于生命周期结束回调的持有方最好使用wp保存观察者。等到事件真的到来时再promote如果已经失效就跳过回调避免通过悬空裸指针调用一个已经析构的对象。这比让观察者自己清理注册状态要省心得多。3.5 工程配置与依赖小提示在AOSP或系统源码环境里使用这套智能指针不需要额外下载依赖直接#include utils/RefBase.h这类头文件即可。模块的Android.bp或Android.mk里通常已经链了libutilssp和wp都在这条依赖链里。如果你只是写一个独立NDK库并不依赖Android系统组件那我建议直接使用标准库智能指针省去对环境依赖的管理成本。还有一种情况是只想在NDK里用到sp的便利性但又不想链接整套libutils。这个时候可以选择只包含头文件性质的LightRefBase或者干脆封装一个轻量引用计数基类。这个取舍取决于你的项目约束没有绝对答案。多数非AOSP项目用标准库是更稳妥的选择。4. 避坑实录sp/wp 常见的几类崩溃与排查经验4.1 栈上对象和手动delete引发的release问题最常见的一个低级错误就是把栈上对象交给sp管理。比如Worker stackWorker; spWorker spWorker(stackWorker);sp析构时会调用decStrong最终走到delete。可stackWorker不是堆上new出来的delete一个栈对象会让进程直接崩溃而且崩溃现场往往非常奇怪。RefBase体系的设计意图非常明确对象只在堆上创建然后交给sp。在栈上使用智能指针管理从一开始就违背了基本原则别这么用。另一个高频错误是sp已经接管对象所有权之后又手动delete原始指针Worker* raw new Worker(); spWorker spWorker(raw); delete raw; // 错误所有权已转移给spdelete raw之后spWorker内部还保留着这个裸指针等到spWorker析构时第二次delete双重释放就来了。这类错误在code review阶段其实很容易发现只要看到“有关系指向RefBase子类的裸指针出参”就要拉响警报。我的建议是凡是继承RefBase的对象所有权语义必须高度明确。谁第一次把它包进sp谁就是这一生命周期的接管者。其他模块想用拿到的是sp或wp副本而不是裸指针。如果确实为了系统接口不得不裸指针过一道那也必须是“借用”语义用完立刻丢弃禁止保存。4.2 多线程场景下的引用计数黑锅很多人以为sp的计数是原子的就认为整个对象都线程安全了。这部分要区分清楚计数本身的增减确实是原子操作但对象内部的数据成员不会自动得到保护。两个线程同时调用同一个Worker的方法修改成员仍然需要自己加锁sp并不会帮你做任何同步。还有一种更隐蔽的情况一个线程正在通过sp调用对象方法另一个线程把最后一个sp释放了导致对象析构。这时候前一个线程的方法还在执行中可能会访问到free之后的内部状态。要避免这类问题通常要把“正在使用”的持续时间段持有一份sp变量而不是在使用期间只靠裸指针临时取数。// 推荐在整个使用区间持有sp auto locked mWeakRef.promote(); if (locked ! nullptr) { locked-doWork(); // 这里locked一直有效 }有些系统代码会用一个sp局部变量来“钉住”对象这个方法本身没问题关键是要保证提升成功以及作用域覆盖完整。如果业务逻辑非常复杂对象内部多个成员需要协同访问还是老老实实加锁再合理安排锁的粒度别指望智能指针能解决并发正确性。4.3 promote空指针和时间窗问题wp.promote()返回空sp的时机常常被低估。对象可能在promote调用之前已经析构也可能在检查完之后、真正使用前被迫析构后者是一个经典的时间窗问题。标准库weak_ptr也面临类似的竞争窗口没有彻底消灭的办法只能通过使用方式降低风险。在实际项目中我习惯把“promote 使用”放进同一个临界区或者同一段执行流内尽量不跨线程异步操作提升后的sp。如果某个任务必须在另一个线程执行就把提升后的sp作为任务参数传递进去让任务自己持有强引用而不是在任务内部再对wp做二次promote。二次promote意味着从“强引用”又退回“弱引用”把生命周期风险重新引入进来。排查这类问题时一个比较直接的方法是打印每次promote前后的强引用计数。结合日志判断对象是在哪个阶段消失的。如果崩溃现场出现在wp对应的类析构里还可以检查是不是有谁把wp对象跨越线程边界传递了导致内部计数器状态孤岛。4.4 实用排查手段日志、计数与Sanitizer排查native智能指针问题我通常按顺序做三件事。第一在构造和析构函数里加上唯一的LOG确认对象创建和销毁的时机。引用计数问题最怕看不出“谁多delete了一次”有了构造析构日志至少能先确认对象是否提前释放。第二需要时打印getStrongCount()观察强引用数量变化是否符合预期。如果某个操作之后计数没有回到0说明还有sp残留往上游找谁多保存了一份如果计数出现负数那基本可以肯定是有人手动delete或者栈对象参与导致计数错乱。第三针对疑似内存越界或悬空用AddressSanitizer/LSan这类工具在调试版本上跑一遍。AOSP的模块支持配置sanitizer跑起来往往能直接定位到错误的释放点。不过要注意智能指针本身会生成很多临时对象Sanitizer报出的某些“heap-use-after-free”可能需要结合构造析构日志一起看才能判断是真实问题还是误报。5. 选型建议sp/wp 与标准库智能指针怎么搭档5.1 一张表快速决策如果项目代码已经跑在AOSP环境你写的是系统组件、Framework服务、HIDL/AIDL实现或与Binder深度耦合的模块那么跟随原生生态用sp/wp是最省事的选择。好处是跟系统库的接口风格一致也方便利用RefBase内置的弱引用和生命周期回调。如果项目是独立NDK库、纯算法、SDK或者可移植中间件那么标准库智能指针更合适。它不依赖libutils跨平台编译顺畅团队成员也更容易用shared_ptr的心智去理解代码。强行在独立库中引入sp反而会带来依赖和交付上的麻烦。使用场景推荐工具原因AOSP系统组件、Binder服务sp/wp与系统生态一致生命周期回调方便Framework Native层对象缓存wp配合sp弱引用观察不阻碍释放NDK独立库中共享对象std::shared_ptr不依赖libutils可移植跨模块临时借用不共享所有权std::unique_ptr所有权简单清晰算法、内存池、内部结构std::unique_ptr或裸指针无共享诉求过度设计没必要5.2 新代码的推荐姿势新写AOSP模块时我自己的习惯是核心生命周期对象默认继承RefBase用sp持有外部间接引用全部用wp对外API只暴露sp和wp隐藏一切裸指针。这样虽然代码里多了一些类型约束但长期维护成本显著降低因为对象的生老病死都统一走同一套规则。如果是纯业务native库我反而会尽量控制动态内存的暴露面。能用unique_ptr解决的就不用shared_ptr能用值语义解决的就不搞指针。引用计数是工具而不是教条一个对象如果确实只有唯一所有者强行上shared_ptr或sp都只会引入不必要的复杂度。还有一个值得推荐的做法在RefBase子类里重写onLastStrongRef回调把对外资源的释放、监听器的注销放进去。这样就算多个模块引用同一个对象也不需要靠某个人记着“最后一把锁在哪里释放”系统自动在最合适的时机通知你做收尾。这个方法在管理缓存、窗口句柄、文件描述符时尤其好用。结合我自己这些年写native代码的经验最实用的一条建议是不要混合记忆两套智能指针的细节写系统模块时干脆忘掉shared_ptr那套写独立库时忘了sp和省事。其实它们的内核都是“计数适时释放”区别主要在控制块的位置和生命周期策略的灵活度上。真正决定代码稳不稳的永远是所有权边界是否清晰是不是有人偷偷拿了裸指针又把责任推给智能指针。写代码的时候心里先画一张生命周期图再决定手上该拿sp、wp还是unique_ptr大多内存问题都不会出现。

相关新闻

UI/UX Pro Max Skill:从需求理解到设计交付的全链路实战指南

UI/UX Pro Max Skill:从需求理解到设计交付的全链路实战指南

做设计这些年,我越来越觉得“UI/UX Pro Max Skill”不是一个具体的软件技巧,而是一整套把产品从“能用”推到“好用”再到“爱用”的能力组合。今天这篇小记,是我自己从需求理解、信息架构、视觉表达到开发交付全链路踩过的坑和攒下的经验&am…

2026/10/14 5:29:14 阅读更多 →
Agent落地为何沦为改PPT工具?企业级Agent设计与人机协作实践

Agent落地为何沦为改PPT工具?企业级Agent设计与人机协作实践

1. 从“改PPT”说起:Agent落地最真实的尴尬过去一年,Agent这个词被反复提起,几乎每一场发布会、每一份行业报告都绕不开它。大厂接连降价,API调用成本一路走低,按理说企业应该大规模用起来才对。但如果你真的去问一圈一…

2026/10/14 5:29:14 阅读更多 →
高校校园停车场系统开发实战:SSM框架全流程设计与实现

高校校园停车场系统开发实战:SSM框架全流程设计与实现

高校校园停车场系统,这个题目在计算机类毕设清单里出现的频率相当高,属于那种“看起来简单、做好很难”的典型题目。我帮人看过不少版本的类似项目,自己也动手写过一版完整的SSM框架实现。这个系统本质上是把高校校园里车辆进出、车位分配、费…

2026/10/14 5:29:14 阅读更多 →

最新新闻

把Antigravity封装成外部Skill,让Codex/Claude Code突破上下文与配额墙

把Antigravity封装成外部Skill,让Codex/Claude Code突破上下文与配额墙

最近在折腾 Codex 和 Claude Code 的混合工作流时,我遇到了一个很实际的问题:单次会话的上下文窗口有限,而一些任务又特别吃资源,反复把代码贴进贴出,很快就撞上了配额墙。后来我想到一个办法——把 Google Antigravit…

2026/10/14 6:16:25 阅读更多 →
AnyPS5:局域网内聚合PS5存档备份、奖杯统计与串流控制的本地工具

AnyPS5:局域网内聚合PS5存档备份、奖杯统计与串流控制的本地工具

最近在做的一个小项目,名字叫 AnyPS5,起因挺朴素的:我自己手头有两台不同型号的主机,平时要在它们之间来回切换着玩。但存档散落在不同设备上,每次都要手动导来导去;想看个奖杯统计,要么开网页等…

2026/10/14 6:16:25 阅读更多 →
项目管理十五至尊图解析与实战应用

项目管理十五至尊图解析与实战应用

1. 项目管理知识体系全景解析在项目管理领域摸爬滚打十几年,我见过太多同行被各种框架图表绕得晕头转向。今天要聊的这个"十五至尊图"堪称项目管理界的"武功秘籍",它把PMBOK的十大知识领域和五大过程组用一张矩阵图完美呈现。第一次…

2026/10/14 6:16:25 阅读更多 →
开源年会进化论:从“同好聚会”到开发者年度节点

开源年会进化论:从“同好聚会”到开发者年度节点

1. 为什么一场开源年会能上得了报纸,还能拿下“最受开发者欢迎”我是在朋友圈刷到这条消息的:COSCon‘25 第十届中国开源年会登上了《中国日报》,同时被思否评为了“最受开发者欢迎的技术活动”。说实话,第一反应不是“厉害”&…

2026/10/14 6:16:25 阅读更多 →
今天周几?JS两行代码背后:getDay()跨语言映射与时区陷阱全解析

今天周几?JS两行代码背后:getDay()跨语言映射与时区陷阱全解析

这个标题我太熟了。刚学编程那阵子,天天在控制台里敲new Date(),盯着那一长串输出发懵:年份、月份、日期、时分秒都在眼前,唯独“今天周几”这个最常用、最直觉的信息,反而要再查一眼文档才能拿到。后来才懂&#xff0…

2026/10/14 6:16:25 阅读更多 →
Java面试必看:3大核心技巧轻松拿offer

Java面试必看:3大核心技巧轻松拿offer

不少朋友常常发送私下消息给我, 向我抱怨说, 他们在参加 Java 这个编程语言相关职位面试的时候, 会碰到一些让人头痛的情况(这里, 我从里面挑选出了几个比较具有代表性的例子来说明):不管是求职还是为了晋升, 面试是我们谁都不能逃避的一件事情。除了低头…

2026/10/14 6:15:24 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →