Chromium WeakPtr 深度解析:从生命周期管理到线程安全的全面指南

C++中的Thunk技术和它的使用场景 阅读详情

引言:一个看似简单却深藏玄机的问题

在 Chromium 开发社区中,经常能看到这样的对话:

初级开发者:"既然用了 WeakPtr,为什么还要手动判空?WeakPtr 不是能自动检测对象是否有效吗?"

资深开发者:"这是一个好问题,但答案比你想象的要复杂..."

这种看似简单的困惑,实际上触及了 Chromium 架构中最核心的设计哲学之一。今天,我们将深入探讨 WeakPtr 的本质,揭示它为什么不是"高级版空指针",以及如何在复杂的多线程环境中安全地使用它。

第一部分:WeakPtr 的真实身份——生命周期卫士

1.1 核心认知的颠覆

WeakPtr 不是 "高级版空指针判断",它是 "生命周期安全卫士"。

这两个概念有着本质的区别:

检查类型解决的问题错误来源WeakPtr 能否解决
入口判空API 契约违反调用方传入非法参数❌ 不能
WeakPtr 判空生命周期失效对象在操作过程中被销毁✅ 专门解决

1.2 为什么 WeakPtr 处理不了 nullptr?

让我们看一个致命的反例:

WebContents* web_contents = nullptr;
base::WeakPtr<WebContents> weak = web_contents->GetWeakPtr(); // 💥 BOOM!

这里会直接崩溃,甚至连 GetWeakPtr() 都调不了。原因在于:

WeakPtr 是从对象内部的 WeakPtrFactory 生成的,工厂必须先存在。

如果对象根本不存在,工厂都没有,你拿什么造 WeakPtr?

1.3 WeakPtr 的工作原理揭秘

让我们看看 Chromium 源码中 WeakPtr 的实现精髓:

// 简化版的 WeakPtr 工作原理
template <typename T>
class WeakPtr {
 public:
  WeakPtr() : ptr_(nullptr), flag_(nullptr) {}
  
  explicit WeakPtr(const T* ptr) {
    if (ptr) {
      // 从对象的 WeakPtrFactory 获取引用
      flag_ = ptr->weak_factory_.GetWeakFlag();
      ptr_ = ptr;
    }
  }
  
  T* get() const {
    // 关键:先检查 flag_ 是否有效
    return flag_ && flag_->is_valid() ? ptr_ : nullptr;
  }
  
  operator bool() const { return get() != nullptr; }
  
 private:
  T* ptr_;
  scoped_refptr<WeakFlag> flag_;  // 共享的弱引用标志
};

// 在对象内部
class WebContents {
 public:
  base::WeakPtr<WebContents> GetWeakPtr() {
    // 注意:调用者是 this,必须非空!
    return weak_factory_.GetWeakPtr();
  }
  
 private:
  base::WeakPtrFactory<WebContents> weak_factory_{this};
};

可以看到,GetWeakPtr() 是一个成员函数,调用者必须是有效的 this 指针。WeakPtr 系统从不承诺处理原始指针为空的场景,那是调用者的责任。

第二部分:多线程环境下的 WeakPtr 安全性

2.1 经典案例研究

考虑 Chromium 中的实际代码:

// static
void Canvas2DLayerBridge::HibernateOrLogFailure(
    base::WeakPtr<Canvas2DLayerBridge> bridge,
    base::TimeTicks /*idleDeadline*/) {
  if (bridge) {
    bridge->Hibernate();
  } else {
    ReportHibernationEvent(
        CanvasHibernationHandler::HibernationEvent::
            kHibernationAbortedDueToDestructionWhileHibernatePending);
  }
}

如果两个线程同时执行这个函数,会发生什么?

线程A: if (bridge)  // 检查通过
线程B: if (bridge)  // 检查通过
线程B: bridge->Hibernate()  // 执行成功
[对象被销毁]
线程A: bridge->Hibernate()  // ❓ 会崩溃吗?

2.2 答案揭秘

答案是不会崩溃。 原因在于 Chromium 的 WeakPtr 实现保证了:

  1. 线程安全的有效性检查:if (bridge) 检查是原子的、线程安全的

  2. 安全的解引用机制:即使对象在检查后被销毁,调用成员函数也会安全地变为空操作

更深入地说,WeakPtr 的实现使用了引用计数的 WeakFlag:

class WeakFlag : public RefCountedThreadSafe<WeakFlag> {
 public:
  bool is_valid() const { 
    // 原子操作,线程安全
    return AtomicRefCountIsOne(&ref_count_);
  }
  
  void Invalidate() {
    // 对象销毁时调用,使所有 WeakPtr 失效
    AtomicRefCountDec(&ref_count_);
  }
};

2.3 跨线程场景的考虑

对于 WebContents 这样的 UI 对象,Chromium 有一个重要原则:UI 对象必须在 UI 线程访问。但是 WeakPtr 本身可以跨线程传递和检查。

// 在 IO 线程
void OnDataReceived(base::WeakPtr<WebContents> weak_contents) {
  // 可以安全检查,但不能直接调用
  if (!weak_contents)
    return;
    
  // 必须 PostTask 到 UI 线程操作
  content::GetUIThreadTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&WebContents::DoSomething, weak_contents));
}

// 在 UI 线程
void WebContents::DoSomething() {
  // 这里才是安全的操作点
}

第三部分:深度探讨——UI 线程中的 WeakPtr 安全性

3.1 一个关键的问题

许多开发者有这样的疑问:

"webcontent 只要不跨线程,当前任务只要没野指针,就不用考虑任务结束过程中野指针的情况了对吧?"

基本正确,这是一个非常危险的假设!(当然如果自己能保证在这个任务粒度里面不会释放对象也行)

3.2 为什么这个假设是危险的?

场景分析
void MyClass::DoSomethingOnUIThread() {
  // 假设 web_contents 当前是有效的
  WebContents* web_contents = GetCurrentWebContents();
  
  // 执行一系列操作...
  web_contents->Step1();
  web_contents->Step2();
  
  // 这里 web_contents 会变成野指针吗?
  // 你的假设:"只要我在同一个任务中,就不会"
}
危险的原因
  1. UI 线程上也可能发生对象销毁:

void MyClass::DangerousOperation(WebContents* web_contents) {
  web_contents->StartOperation();
  
  // 这里可能触发其他事件,导致 web_contents 被销毁
  // 例如:用户点击关闭按钮、JavaScript 调用 window.close()
  web_contents->DoSomething();  // 💥 潜在危险!
}
  1. Chromium 中的"任务内自毁"模式:

class TabStripModel {
 public:
  void CloseTab(int index) {
    WebContents* contents = GetWebContentsAt(index);
    
    // 触发关闭 - 可能同步销毁!
    contents->WillClose();
    
    // 这里 contents 可能已经部分析构!
    // 继续使用是危险的
  }
};

3.3 更深入的问题:多次检查的必要性

回到我们的核心问题:

如果确实能保证 DoSomething() 不会销毁对象,那么 DoMore() 前的检查是不是多余的?

让我们分析代码:

void MyClass::EvenSaferOperation() {
  base::WeakPtr<WebContents> weak_contents = GetWebContentsWeakPtr();
  
  if (!weak_contents)
    return;
    
  weak_contents->DoSomething();
  
  // 问题:这个检查必要吗?
  // 如果 DoSomething() 保证不销毁对象,是不是可以省略?
  if (!weak_contents)  // 🧐 真的需要吗?
    return;
    
  weak_contents->DoMore();
}
技术分析

从纯技术角度看,如果 DoSomething() 确实保证不销毁对象(包括不触发任何可能间接销毁对象的操作),那么这个检查确实是多余的。

但是,从工程实践角度看,这个检查几乎总是必要的,原因如下:

3.4 为什么工程中需要多次检查?

1. 代码演化的不确定性

今天的 DoSomething() 可能不销毁对象,但明天的代码修改呢?

// 版本1:安全
void WebContents::DoSomething() {
  // 只是读取数据
  return GetData();
}

// 版本2:危险
void WebContents::DoSomething() {
  // 新增功能:在特定条件下关闭自己
  if (ShouldClose()) {
    Close();  // 可能导致对象销毁!
  }
}
2. 复杂的调用链
void WebContents::DoSomething() {
  // 看起来无害...
  NotifyObservers();
  
  // 但是某个观察者可能:
  Observer1::OnWebContentsEvent() {
    // 决定关闭这个 WebContents
    web_contents->Close();
  }
}
3. 防御性编程的最佳实践

在复杂的系统如 Chromium 中,防御性编程是必需的,而不是可选的。

第四部分:核心原则——以"任务"为粒度进行生命周期管理

4.1 Chromium 的异步编程哲学

Chromium 的架构设计强调 "任务驱动" 的生命周期管理。每个任务都是原子性的,任务之间通过 WeakPtr 确保安全。

4.2 关键洞察

WeakPtr 保护的是"任务间"的安全,不是"任务内"的安全。

考虑这个场景:

void MyClass::StartAsyncOperation() {
  base::WeakPtr<MyClass> weak = weak_factory_.GetWeakPtr();
  
  base::ThreadPool::PostTask(
      FROM_HERE,
      base::BindOnce(&MyClass::OnOperationComplete, weak));
}

void MyClass::OnOperationComplete(base::WeakPtr<MyClass> weak) {
  // WeakPtr 保证这个任务能看到对象是否还存在
  if (weak) {
    weak->ProcessResult();
  }
}

第五部分:工程实践——为什么 Chromium 需要"双重判空"?

5.1 UI 对象的复杂性来源

在 Chromium 中,UI 对象(如 WebContents、Tab、Window)的生命周期极其复杂,可能被多种事件终结:

  1. 用户操作:关闭标签页、关闭窗口

  2. 系统事件:内存不足、进程崩溃

  3. 配置变更:Profile 切换、设置更改

  4. 异步回调:网络请求完成、定时器触发

  5. 跨进程通信:扩展 IPC、渲染器进程消息

5.2 标准的安全模式

因此,Chromium 形成了标准的"双重防护"模式:

void MyFeature::DoSomethingWithWebContents(WebContents* web_contents) {
  // 第一层:API 契约检查
  // 防止调用方传入非法参数
  if (!web_contents)
    return;
  
  // 第二层:生命周期保护
  base::WeakPtr<WebContents> weak = web_contents->GetWeakPtr();
  
  // 执行可能耗时的操作
  FetchDataFromNetwork(base::BindOnce(
      &MyFeature::OnDataFetched, weak));
}

void MyFeature::OnDataFetched(base::WeakPtr<WebContents> weak, 
                              const std::string& data) {
  // 第三层:最终使用前的检查
  // 对象可能在网络请求过程中被销毁
  if (!weak)
    return;
    
  // 安全使用
  weak->DisplayData(data);
}

5.3 WeakPtr 的局限性:什么情况它保护不了?

1. 循环引用导致的延迟销毁
class Parent {
  base::WeakPtrFactory<Parent> weak_factory_{this};
  std::unique_ptr<Child> child_;
};

class Child {
  base::WeakPtr<Parent> parent_;
  
  void DoSomething() {
    if (parent_) {
      // 这里 parent_ 可能即将被销毁
      // 但 WeakPtr 检查仍然通过
      parent_->CallSomething();
    }
  }
};
2. 同一任务内的自毁操作
void MyClass::DestroySelf() {
  base::WeakPtr<MyClass> weak = weak_factory_.GetWeakPtr();
  
  // 危险:在同一个任务中销毁自己
  delete this;
  
  // 这里的 weak 检查可能不可靠
  if (weak) {  // ❌ 未定义行为
    // ...
  }
}

第六部分:高级话题——WeakPtr 的性能与权衡

6.1 WeakPtr 的性能开销

虽然 WeakPtr 提供了强大的安全性,但它不是没有成本的:

// WeakPtr 检查的开销
bool IsValid() const {
  // 需要:
  // 1. 检查 flag_ 是否非空
  // 2. 检查 flag_ 是否有效(原子操作)
  // 3. 返回结果
  return flag_ && flag_->is_valid();
}

6.2 何时可以省略检查?

在某些严格控制的场景下,如果满足以下所有条件,可以考虑减少 WeakPtr 检查:

  1. 私有代码:不是公开 API

  2. 短期对象:对象生命周期完全可控

  3. 同步操作:不涉及异步或回调

  4. 简单操作:不会触发复杂的事件链

// 示例:严格控制的场景
void MyClass::InternalHelper() {
  // 这个函数:
  // 1. 是私有方法
  // 2. 只在对象生命周期早期调用
  // 3. 执行简单同步操作
  
  base::WeakPtr<MyClass> weak = weak_factory_.GetWeakPtr();
  if (!weak)
    return;
    
  // 因为上下文完全可控,这里省略二次检查
  weak->SimpleOperation1();
  weak->SimpleOperation2();  // 假设 SimpleOperation1 不会销毁对象
}

6.3 自动化检查工具

Chromium 社区开发了一些工具来帮助管理 WeakPtr 的使用:

// 使用编译时检查
#define WEAK_PTR_CHECK(weak) \
  CHECK(weak) << "WeakPtr unexpectedly invalid at " << __FILE__ << ":" << __LINE__

void MyClass::Operation() {
  base::WeakPtr<MyClass> weak = weak_factory_.GetWeakPtr();
  WEAK_PTR_CHECK(weak);
  
  // 如果 weak 无效,程序会立即崩溃(调试时)
  // 而不是产生未定义行为
}

第七部分:实战指南——WeakPtr 的最佳实践

7.1 基本规则

1. 始终进行入口判空
// 正确
void Process(WebContents* contents) {
  if (!contents)  // 必须的
    return;
    
  base::WeakPtr<WebContents> weak = contents->GetWeakPtr();
}

// 错误 - 可能导致崩溃
void Process(WebContents* contents) {
  // 假设 contents 非空是危险的
  base::WeakPtr<WebContents> weak = contents->GetWeakPtr();
}
2. 使用 WeakPtr 进行异步边界保护
void StartAsyncOperation() {
  base::WeakPtr<MyClass> weak = weak_factory_.GetWeakPtr();
  
  base::PostTask(
      FROM_HERE,
      base::BindOnce(&MyClass::OnAsyncComplete, weak));
}

void OnAsyncComplete(base::WeakPtr<MyClass> weak) {
  // 这是 WeakPtr 的主要用途
  if (!weak)
    return;
    
  // 安全操作
}

7.2 进阶技巧

1. WeakPtr 的"延迟绑定"模式
class MyClass {
 public:
  void StartComplexOperation() {
    // 保存 WeakPtr 供后续使用
    operation_weak_ = weak_factory_.GetWeakPtr();
    
    Step1();
  }
  
 private:
  void Step1() {
    if (!operation_weak_)
      return;
      
    // 操作...
    Step2();
  }
  
  void Step2() {
    // 每个步骤都检查
    if (!operation_weak_)
      return;
      
    // 更多操作...
  }
  
  base::WeakPtr<MyClass> operation_weak_;
};
2. 结合智能指针使用
class ResourceManager {
 public:
  void ManageResource(std::unique_ptr<Resource> resource) {
    // 同时保存 unique_ptr 和 WeakPtr
    base::WeakPtr<Resource> weak = resource->GetWeakPtr();
    resources_.emplace_back(std::move(resource), weak);
  }
  
  void UseResource(int id) {
    auto it = FindResource(id);
    if (it == resources_.end())
      return;
      
    // 使用 WeakPtr 检查
    if (!it->weak_ptr)
      return;
      
    it->weak_ptr->Use();
  }
  
 private:
  struct Entry {
    std::unique_ptr<Resource> resource;
    base::WeakPtr<Resource> weak_ptr;
  };
  std::vector<Entry> resources_;
};

7.3 调试与测试

1. 单元测试中的 WeakPtr
TEST(MyClassTest, WeakPtrSafety) {
  auto obj = std::make_unique<MyClass>();
  base::WeakPtr<MyClass> weak = obj->GetWeakPtr();
  
  // 测试1:对象存在时 WeakPtr 有效
  EXPECT_TRUE(weak);
  
  // 测试2:对象销毁后 WeakPtr 失效
  obj.reset();
  EXPECT_FALSE(weak);
  
  // 测试3:使用失效的 WeakPtr 不会崩溃
  weak->Method();  // 应该安全地什么也不做
}
2. 调试断言
void MyClass::DebugOnlyMethod() {
  // 调试构建中有额外检查
  DCHECK(weak_ptr_factory_.HasWeakPtrs());
  
  base::WeakPtr<MyClass> weak = weak_factory_.GetWeakPtr();
  DCHECK(weak);  // 调试时断言
  
  // 发布构建中只有基本检查
  if (!weak)
    return;
}

第八部分:常见陷阱与解决方案

8.1 陷阱1:在析构函数中使用 WeakPtr

// 错误
MyClass::~MyClass() {
  base::WeakPtr<MyClass> weak = weak_factory_.GetWeakPtr();
  // 这时 weak_factory_ 可能已经部分析构!
  if (weak) {  // 未定义行为
    // ...
  }
}

// 正确
MyClass::~MyClass() {
  // 不要在析构函数中获取自己的 WeakPtr
  // 直接使用 this 指针(如果安全)
  Cleanup();
}

8.2 陷阱2:WeakPtr 作为类成员

// 潜在问题
class Container {
 public:
  void StoreWeakPtr(base::WeakPtr<OtherClass> weak) {
    weak_ptr_ = weak;  // 保存别人的 WeakPtr
  }
  
  void UseIt() {
    if (weak_ptr_) {
      weak_ptr_->DoSomething();  // 对象可能已被销毁
    }
  }
  
 private:
  base::WeakPtr<OtherClass> weak_ptr_;  // 保存 WeakPtr 作为成员
};

// 更好的设计
class Container {
 public:
  void UseOther(OtherClass* other) {
    if (!other)
      return;
      
    // 临时使用,不长期保存
    base::WeakPtr<OtherClass> weak = other->GetWeakPtr();
    if (weak) {
      weak->DoSomething();
    }
  }
};

8.3 陷阱3:忽略 WeakPtr 的线程约束

// 危险
void WorkerThread::Process(base::WeakPtr<UIObject> weak) {
  if (weak) {
    // 错误:在非UI线程访问UI对象
    weak->UpdateUI();  // 💥 可能崩溃
    
    // 正确做法
    content::GetUIThreadTaskRunner()->PostTask(
        FROM_HERE,
        base::BindOnce(&UIObject::UpdateUI, weak));
  }
}

第九部分:未来展望与替代方案

9.1 WeakPtr 的演进

Chromium 团队一直在改进 WeakPtr 系统:

// 未来的可能改进
template <typename T>
class CheckedWeakPtr {
 public:
  // 编译时检查
  T* operator->() {
    static_assert(std::is_base_of<SupportsWeakPtr, T>::value,
                  "T must support WeakPtr");
    return get();
  }
  
  // 运行时调试信息
  std::string GetDebugInfo() const {
    if (!flag_) return "No weak flag";
    return flag_->GetCreationStack();
  }
};

9.2 替代方案比较

方案优点缺点适用场景
WeakPtr标准、安全、线程安全有一定开销通用场景
base::Unretained无开销不安全、需手动管理简单同步操作
base::ScopedRefPtr强引用、自动管理可能造成循环引用需要所有权的场景
裸指针 + 手动管理零开销极易出错性能关键代码

9.3 选择指南

// 场景1:异步回调
// ✅ 使用 WeakPtr
base::PostTask(FROM_HERE,
               base::BindOnce(&MyClass::Callback,
                              weak_factory_.GetWeakPtr()));

// 场景2:同步、性能关键
// ✅ 可能使用裸指针(谨慎!)
void ProcessFrame(MyClass* obj) {
  // 调用者保证 obj 有效
  obj->Process();
}

// 场景3:需要所有权
// ✅ 使用 unique_ptr 或 ScopedRefPtr
class Manager {
  std::vector<std::unique_ptr<Resource>> resources_;
};

第十部分:总结与思考

10.1 核心要点回顾

  1. WeakPtr 不是空指针的替代品:它解决的是生命周期问题,不是参数验证问题

  2. 双重防护是必要的:入口判空保护 API 契约,WeakPtr 判空保护生命周期

  3. 线程安全是设计保证的:WeakPtr 可以在多线程环境中安全使用

  4. 防御性编程是关键:在复杂系统中,安全的假设比性能更重要

10.2 哲学思考

Chromium 的 WeakPtr 设计反映了一个深刻的工程哲学——明确的责任分离:

  • API 契约检查是调用者的责任

  • 生命周期管理是被调用者的责任

  • WeakPtr 让这种分离变得清晰且安全

这种设计哲学使得 Chromium 能够在数百万行代码的规模下,依然保持高度的可维护性和可靠性。

10.3 给开发者的建议

  1. 开始时严格:对新代码采用最严格的安全标准

  2. 理解上下文:在优化时,确保完全理解代码的调用上下文

  3. 代码即文档:清晰的 WeakPtr 使用模式是最好的文档

  4. 测试边界条件:特别测试对象在操作过程中被销毁的场景

10.4 最后的提醒

记住这句 Chromium 开发者的经验之谈:

"在 Chromium 中,如果你认为某个 WeakPtr 检查是多余的,那么你很可能还没有完全理解那个代码路径的所有可能性。"

WeakPtr 是 Chromium 架构中众多精妙设计之一,它的存在提醒我们:在构建复杂系统时,安全性、可靠性和可维护性往往比极致的性能更重要。理解并正确使用 WeakPtr,是成为 Chromium 高级开发者的重要一步。


扩展阅读:如果你对这个话题感兴趣,还可以研究 Chromium 中的 base::Unretained、base::Bind 的生命周期管理,以及 Mojo 接口中的 WeakPtr 使用模式,这些都是 Chromium 架构中生命周期管理的精彩实践。

实战练习:尝试在 Chromium 代码库中搜索 weak_factory_,观察不同的使用模式,理解每种模式背后的设计意图,这是提升 Chromium 开发技能的最佳途径。

深入解析 Chromium Mojo IPC:跨进程通信原理与源码实战 本文深入解析Chromium浏览器中的Mojo IPC机制,这一高性能跨进程通信框架支撑着现代浏览器多进程架构的运行。文章从Mojo的五个核心概念(MessagePipe、Handle、Interface、Receiver/Remote、Bindings)切入,详细剖析了其数据流、线程模型和异步机制。通过源码分析展示了MessagePipe的底层实现、SimpleWatcher的事件监听机制,以及接口自动生成类的运作原理。最后提供了实战示例和性能优化建议,包括使用SharedBuffer减少拷贝、合理绑定线 阅读详情

相关推荐

深入理解浏览器渲染引擎:底层机制与性能优化实战

本文深入探讨了现代浏览器渲染引擎的工作原理,特别是Blink和V8引擎的协作机制。文章首先概述了浏览器的多进程架构,包括浏览器进程、渲染进程、GPU进程和网络进程的功能。接着,详细解析了渲染引擎的核心步骤,从HTML和CSS的解析到DOM和CSSOM的构建,再到渲染树的形成、布局、绘制和最终的合成阶段。文章还探讨了JavaScript引擎与渲染引擎的交互方式,以及如何通过优化策略减少重排和重绘,提升页面渲染性能。最后,提供了Chromium源码的调试路径和实用建议,帮助开发者更好地理解和优化渲染流程。

John_ToStr的博客 1777

chrome源码中WeakPtr 跨线程使用详解:原理、风险与最佳实践

WeakPtr 跨线程使用详解:原理、风险与最佳实践

John_ToStr的博客 1471

深入解构 Chromium 升级流程与常见问题解决方案

本文详细记录了从老旧Chromium版本升级至114版本的完整流程,涵盖版本评估、代码迁移、构建适配等功能环节。重点分析了升级过程中面临的技术挑战,包括API接口变更、Mojo架构调整、Blink层重构及沙箱策略强化等问题,并提供了针对性的解决方案。文章特别强调了模块解耦设计、沙箱权限审查和性能优化等关键点,分享了对齐工具链、回归测试和灰度发布等实践经验。最后总结了定期升级、维护兼容层和利用社区资源等核心建议,为浏览器内核升级提供了实用技术参考。

John_ToStr的博客 1453

Chromium Base学习笔记 —— Weakptr

WeakPtr 不会影响Object的声明周期。 任何其他的对象,包括它自己在任何时间都可以delete。 WeakPtr存在的意义就是保证其他对象访问它的时候的安全性(有可能被意外delete,所以访问到Null等) // EXAMPLE: class Controller { public: void SpawnWorker() { Worker::StartNew(w

benben198621的博客 1384

SolidWorks 2022 学习(一)软件安装

接下来是安装SolidWorks,右键SolidWorks.2022.SP0.Premium.DVD.iso,选择装载。然后以管理员身份运行SolidWorks_Flexnet_Server目录下的server_install.bat。更改需要安装的产品,以及安装路径,并勾选接受条款,点击现在安装,会弹出如下窗口。然后以管理员身份运行setup.exe,开始安装solidworks。下载链接会在文章末尾给出,下载完成的文件如下图所示。双击注册表文件,然后点击确定。保持不动,点击确定,开始安装。

qq_38383364的博客 3123

大模型-internvl高通qnn运行源码解读

模型链接:https://huggingface.co/OpenGVLab/InternVL2-2B论文官方简要说明 https://internvl.github.io/blog/2024-07-02-InternVL-2.0中文解读 https://zhuanlan.zhihu.com/p/702946079在线demo https://internvl.opengvlab.com/

点滴的岁月 1831

Chromium 并发编程:base::WeakPtr 与 base::WrapRefCounted深度解析

本文深入对比了Chromium中base::WrapRefCounted(this)和base::WeakPtr两种跨线程异步任务处理的解决方案。base::WrapRefCounted通过原子引用计数实现强引用,确保对象存活但可能导致生命周期失控;base::WeakPtr采用弱引用机制,支持及时释放但需遵守线程限制。文章详细分析了两者的优劣势、典型应用场景及常见陷阱,并提供了代码改造建议。对于UI组件应优先使用WeakPtr,而持久化任务则适合WrapRefCounted。最后给出了从WrapRefCo

John_ToStr的博客 402

COLMAP在Ubuntu下的编译陷阱与实战避坑指南——从环境配置到三维重建全流程

本文详细介绍了在Ubuntu系统下编译和配置COLMAP三维重建工具的全流程,包括环境准备、依赖库安装、CUDA加速配置以及常见编译问题的解决方案。通过实战案例演示了从图像特征提取到稠密重建的完整步骤,并提供了性能优化和问题排查的实用技巧,帮助用户高效完成三维重建任务。

weixin_29003437的博客 1048

贪心算法——最大整数问题详解

贪心算法——最大整数问题详解: [最大整数]设有n个正整数,将它们连接成一排,组成一个最大的多位整数。 例如:n=3时,3个整数13,312,343,连成的最大整数为34331213。 又如:n=4时,4个整数7,13,4,246,连成的最大整数为7424613。 输入:n N个数 输出:连成的多位数 算法分析:此题很容易想到使用贪心法,在考试时有很多

John_ToStr的博客 7773

Groq LPU架构解析:确定性线性处理器如何重塑AI推理

语言模型推理正从‘通用算力堆叠’转向‘确定性硬件定制’。LPU(Language Processing Unit)作为一种面向大模型推理的领域专用处理器,摒弃传统GPU的并行调度、多级缓存与动态执行范式,转而采用空间计算、静态编译与单线程线性流水线设计,实现纳秒级延迟可控性和92%+的HBM带宽利用率。其核心价值在于将模型结构、内存访问、时序路径全部在编译期固化,从而消除运行时抖动——这正是当前MLOps工程师应对A100显存碎片、vLLM调度开销与P99延迟不稳等痛点的关键技术路径。Groq 3 LPU与

weixin_30599521的博客 325

RAG——RAG 索引(文档解析技术)

本文介绍了RAG系统中文档解析的关键技术,重点分析了如何通过LangChain的Document Loaders处理多种格式文档。文章指出高质量文档解析对RAG系统效果的决定性作用,并详细讲解了PDF、TXT、Word等常见格式的解析方法。作者提供了代码示例和Gitee开源项目链接,特别强调了PDF解析的深入方案,同时介绍了相关依赖库的安装配置。文章还展示了如何定义通用文档加载方法,为开发者提供了实用的技术参考。

小志的博客 750

Windows Hook案例分析与技术探索

Hook是Windows中提供的一种用以替换DOS下“中断“的系统机制,中文译为“挂钩”或“钩子”。在对 特定的系统事件进行Hook后,一旦发生已Hook事件,对该事件进行Hook的程序就会收到系统的通知, 这时程序就能在第一时间对该事件做出响应。 钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有 到达目的程序前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理 (改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。..

John_ToStr的博客 7128

测试dali协议的软件,DALI2.0和DALI1.0完美兼容同一个模块,测试每项可过协议

DALI2.0和DALI1.0完美兼容同一个模块,测试每项可过协议深圳聚积智能 夏先生 13246760327 QQ 349098308■IEC62386-102(V2.0)通过测试内容IEC62386-102/2.1/Test preambleIEC62386-102/3.1/Polarity testIEC62386-102/3.2/Maximum and minimum system v...

weixin_35343788的博客 1349

浏览器无痕模式机制解析:它与正常模式究竟有何不同?

在日常浏览网页时,很多用户会注意到浏览器提供了“无痕模式”、“隐私窗口”或“InPrivate模式”等选项。这个功能常常被认为是“匿名上网”,但从技术实现角度来看,无痕模式到底和普通浏览模式有什么不同?它真的能完全不留痕迹吗?又有哪些场景下开发者要注意两种模式的行为差异? 本文将从浏览器实现机制出发,系统地讲解无痕模式的原理、与普通模式的区别、以及它在开发调试中的表现差异和典型使用场景。

John_ToStr的博客 6026

openai联合创始人用1000行纯C语言手搓的GPT-2训练代码

不久之前,特斯拉前 AI 总监、OpenAI 联合创始人 Andrej Karpathy 在社交媒体平台 X 上高调宣布,他友好地从 OpenAI 离职,未来将专注于“个人项目”,而后又口口声声说要尝试性地戒掉上网两周,去了 Bhutan(不丹王国)休假。然后就手搓如下代码,我们一起来欣赏.这段代码是一个GPT-2模型的训练实现,包括前向传播、后向传播、参数更新等过程。代码中包含了注释,解释了每个函数和代码块的作用。此外,还有一些辅助函数和结构体,用于数据加载、随机数生成和模型的初始化与释放。这个训练循环还

zhangzhechun的专栏 1207

基于AI的智能开发环境—Trae在Web开发中的应用实战与性能评估【Trae项目实战】

Trae 是一款与 AI 深度集成的开发工具,提供智能问答、代码自动补全和基于 Agent 的 AI 自动编程能力,极大提升开发效率。它具备完备的 IDE 功能,如代码编写、项目管理和源代码管理等,同时还具备强大的 AI 助手,能够提供智能问答、实时代码建议、代码片段生成等服务。开发者可以通过自然语言与 AI 协作,从 0 到 1 开发项目,AI 会根据需求自动生成代码或创建文件。

一键难忘的博客 3万+

CPU 占用升高 ≠ 卡顿:浏览器硬件加速的真正价值

浏览器开启硬件加速后CPU占用升高但运行更流畅的现象属于正常优化:硬件加速将图形任务从CPU主线程转移到GPU处理,虽然GPU调度会消耗部分CPU资源,但显著减轻了主线程负担,带来更流畅的体验。建议多数设备开启该功能,仅在驱动不兼容或低功耗场景下关闭。通过chrome://gpu可验证加速是否生效,开发者还能追踪关键渲染事件进行深度优化。

John_ToStr的博客 2134

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

揭秘浏览器中 Cookie 的真正作用与性能影响

本文深入解析了Cookie在Web开发中的真实作用与性能影响。文章首先澄清了"Cookie能加速请求"的常见误解,指出Cookie不仅不会提升性能,反而可能因增加请求体积和降低缓存命中率而拖慢加载速度。通过分析Cookie的定义、核心作用(状态保持、个性化、行为跟踪)和现代浏览器对其的限制(SameSite、分区存储等),作者强调Cookie是状态管理工具而非性能优化手段。文章提供了实用建议:合理设置作用域、避免存储大数据、为静态资源使用独立域名等,并推荐采用现代缓存策略替代过度依赖Co

John_ToStr的博客 1627

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

关于回调函数跟this指针的一些理解

在C里面,经常需要提供一个函数地址,注册到结构里,然后在程序执行到特定阶段时,回调该函数。创建线程,注册线程运行的主函数就是一个典型的例子。这里以简单的回调实例,说明C++中回调函数为成员函数时有关this指针的问题。由于C++对C的继承关系,C++没有自己的线程封装技术,一般而言我们创建线程时,还是用C的回调函数机制。类似的例子也挺多的。在Java等纯粹的面向对象语言,则不一样,不光有自己的独立

John_ToStr的博客 1543

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

从 base 出发:深入理解 Chromium 自研基础库的体系结构与设计哲学(兼谈为什么不直接用 STL)

Chromium基础库base解析:浏览器内核的底层基石 作为Chromium内核最底层的公共库,base库为整个浏览器架构提供了跨平台一致性的基础支撑。它通过重新封装智能指针、线程模型、容器等核心组件,解决了标准C++库在大型跨平台项目中面临的性能不可控、行为不一致等问题。base库包含内存管理(RefCounted/WeakPtr)、任务调度(TaskRunner/ThreadPool)、事件循环(MessageLoop)、自研容器(flat_map)等核心模块,采用统一抽象层确保不同操作系统表现一致。

John_ToStr的博客 1523

背包问题——动态规划算法详解与实例

动态规划算法详解与实例 一、基本概念     动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。 二、基本思想与策略     基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息

John_ToStr的博客 1512

make_shared、shared_ptr、enable_shared_from_this

make_shared 和 正常的 shared_ptr 构造函数异同!

John_ToStr的博客 1480

Release 与 Debug 的区别及 Release 版本调试指南

摘要: Debug与Release模式在软件开发中存在显著差异:Debug关闭优化、保留调试信息,便于调试但性能差;Release开启优化、去除冗余检查,性能好但调试困难。Release版本易因未初始化变量、越界访问等问题出现Bug,尤其在线程竞争下更明显。调试Release版本需保留符号信息(如.pdb文件),临时禁用优化,利用日志、Dump文件及工具(如VS/WinDbg/gdb)定位问题。开发者应兼顾Debug阶段的严格测试与Release版本的符号保留,以快速修复线上问题。

John_ToStr的博客 1473

Chrome 扩展安全攻防实录:从攻击面到防御实践

本文系统剖析Chrome扩展安全风险,涵盖其架构组成、权限模型与通信机制,梳理权限滥用、脚本注入、消息信任漏洞等攻击面,结合XSS提权、伪造消息、供应链攻击等典型案例,提出最小权限、输入校验、CSP策略、依赖管理等防御体系,并提供静态检查、动态调试等审计实践。展望Manifest V3下安全演进方向,为开发者与安全研究者提供全面防护指南。

2401_84466325的博客 182
上一篇: 深度剖析 Chromium UI 线程中的 PostTask 机制:从任务粒度到线程协作
下一篇: 进程退出时 C++ 析构到底会不会执行?——从 Chromium 架构看“故意泄漏”的工程哲学
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ปรัชญา แค้วคำมูล

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值