揭秘shared_ptr循环引用:为什么你的内存泄漏了?

shared_ptr循环引用问题以及解决方法 shared_ptr循环引用问题以及解决方法一、shared_ptr循环引用问题例子一例子二例子三二、weak_ptr解决循环引用问题 一、shared_ptr循环引用问题 什么是循环引用,两个对象相互使用shared_ptr指向对方。造成的后果是:内存泄漏 例子一 下面是循环引用的例子 #include <iostream> #include <memory> using namespace std; class A; class B; class A { public: 阅读详情

第一章:揭秘shared_ptr循环引用:为什么你的内存泄漏了?

在C++的智能指针家族中,std::shared_ptr 是管理动态资源生命周期的重要工具。它通过引用计数机制自动释放对象,避免手动调用 delete 带来的内存泄漏风险。然而,当两个或多个对象相互持有对方的 shared_ptr 时,就会形成循环引用,导致引用计数永远无法归零,最终引发内存泄漏。

什么是循环引用

当对象A持有对象B的 shared_ptr,同时对象B也持有对象A的 shared_ptr,析构条件便无法满足。即使外部指针被销毁,彼此的引用计数仍大于0,造成资源无法释放。 例如以下代码:

#include <memory>
#include <iostream>

struct Node;
using NodePtr = std::shared_ptr<Node>;

struct Node {
    Node(int id) : id(id) {}
    int id;
    NodePtr parent;
    NodePtr child;

    ~Node() { std::cout << "Node " << id << " destroyed.\n"; }
};

int main() {
    auto node1 = std::make_shared<Node>(1);
    auto node2 = std::make_shared<Node>(2);

    node1->child = node2;
    node2->parent = node1; // 循环引用形成

    return 0; // 此处不会输出析构信息
}
上述程序运行后,两个节点均未被析构,内存泄漏发生。

如何避免循环引用

关键在于打破循环链。C++提供 std::weak_ptr 来解决此问题。它不增加引用计数,仅观察对象是否存在。 修改方案如下:
  • 将双向关系中的一方改为使用 weak_ptr
  • 通常用于“从属”或“反向”引用,如父节点持子节点的 shared_ptr,子节点持父节点的 weak_ptr
修正后的结构定义:

struct Node {
    int id;
    NodePtr child;
    std::weak_ptr<Node> parent; // 使用 weak_ptr 打破循环
};
此时,当外部引用释放时,引用计数正确归零,对象得以正常析构。
智能指针类型是否增加引用计数适用场景
shared_ptr是共享所有权
weak_ptr否打破循环引用

第二章:shared_ptr的工作原理与引用计数机制

2.1 shared_ptr的核心设计与资源管理模型

shared_ptr 是 C++ 智能指针中最关键的类型之一,采用引用计数机制实现动态资源的共享管理。当多个 shared_ptr 实例指向同一对象时,引用计数自动递增;仅当计数归零时,资源才被释放。

引用计数与控制块结构

每个 shared_ptr 共享一个控制块,包含引用计数、弱引用计数和删除器等元信息。

std::shared_ptr<int> p1 = std::make_shared<int>(42);
std::shared_ptr<int> p2 = p1; // 引用计数从1变为2

上述代码中,make_shared 高效地在同一内存块中构造对象并初始化控制块,避免多次分配。

资源释放流程
  • 每次拷贝构造或赋值操作增加引用计数
  • 析构或重置时减少引用计数
  • 计数为0时调用删除器释放资源

2.2 引用计数的增减时机与线程安全性分析

引用计数的核心在于对象被引用或释放时的精确增减。每当有新指针指向对象,引用计数加一;指针离开作用域或被赋值为 null 时,计数减一。
增减时机示例

type Object struct {
    refCount int
}

func (o *Object) Retain() {
    o.refCount++
}

func (o *Object) Release() {
    o.refCount--
    if o.refCount == 0 {
        // 触发资源回收
        o.cleanup()
    }
}
上述代码中,Retain 在新增引用时调用,Release 在引用失效时调用,确保对象生命周期准确管理。
线程安全性挑战
在多线程环境下,引用计数的增减必须是原子操作,否则会出现竞态条件。例如两个线程同时调用 Release,可能同时读取到 refCount=1,导致重复释放。 使用原子操作或互斥锁可解决此问题:
  • 原子加减:保证 refCount 增减的原子性
  • 内存屏障:防止指令重排影响一致性

2.3 使用shared_ptr避免常见内存错误的实践案例

在现代C++开发中,shared_ptr通过引用计数机制有效防止了内存泄漏和重复释放等问题。
典型使用场景:对象共享生命周期管理
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
{
    std::shared_ptr<MyClass> ptr2 = ptr1; // 引用计数+1
} // ptr2离开作用域,引用计数-1,但对象未销毁
// ptr1仍可安全访问对象
上述代码中,make_shared创建对象并由ptr1持有。当ptr2复制ptr1时,引用计数自动递增。仅当所有共享指针析构后,对象才被释放,避免悬空指针。
对比原始指针的风险
  • 手动delete易遗漏导致内存泄漏
  • 多次delete引发未定义行为
  • 难以追踪共享资源的所有者
shared_ptr将资源所有权透明化,自动管理销毁时机,显著提升代码安全性与可维护性。

2.4 weak_ptr的作用与打破共享所有权的关键意义

在C++智能指针体系中,weak_ptr用于解决shared_ptr因循环引用导致的内存泄漏问题。它不增加对象的引用计数,仅观察由shared_ptr管理的对象状态。
典型使用场景:打破循环引用
当两个对象通过shared_ptr相互持有对方时,引用计数无法归零,造成资源无法释放。此时可将其中一方改为weak_ptr。

#include <memory>
struct Node {
    std::shared_ptr<Node> parent;
    std::weak_ptr<Node>   child;  // 避免循环引用
};
上述代码中,子节点通过weak_ptr引用父节点,不会增加引用计数。访问时需调用lock()获取临时shared_ptr,确保对象仍存活。
关键操作方法
  • lock():返回shared_ptr,若对象已销毁则返回空
  • expired():检查所指对象是否已被释放(非线程安全)
  • reset():释放弱引用

2.5 资源释放过程中的析构行为与陷阱演示

在对象生命周期结束时,析构函数负责清理所持有的资源。若未正确实现,可能导致内存泄漏或重复释放。
常见析构陷阱示例
class FileHandler {
    FILE* file;
public:
    FileHandler(const char* path) {
        file = fopen(path, "w");
    }
    ~FileHandler() {
        if (file) fclose(file); // 正确释放
    }
};
上述代码中,析构函数安全关闭文件句柄。若省略fclose,将导致资源泄露。
典型问题归纳
  • 未释放动态分配的内存
  • 多次释放同一资源引发未定义行为
  • 析构函数抛出异常(C++中应避免)
安全实践建议
使用RAII机制结合智能指针可有效规避手动管理风险。

第三章:循环引用的形成条件与典型场景

3.1 双向链表中父子节点相互持有导致的循环引用

在双向链表中,每个节点通常持有其前驱和后继节点的引用。当父子节点相互强引用时,容易引发循环引用问题,阻碍垃圾回收机制释放内存。
典型结构示例

type ListNode struct {
    Value    int
    Prev     *ListNode  // 指向前驱节点
    Next     *ListNode  // 指向后继节点
}
上述 Go 结构体中,Prev 和 Next 字段形成双向连接。若两个相邻节点的指针同时非空,则构成引用环。
内存管理影响
  • 在手动内存管理语言中(如 C/C++),可能导致内存泄漏;
  • 在带 GC 的语言中(如 Go、Java),可能延迟对象回收,增加内存占用。
合理设计应结合弱引用或显式置空策略,打破不必要的循环依赖。

3.2 观察者模式或信号槽机制中的智能指针误用

在实现观察者模式或信号槽机制时,智能指针的管理尤为关键。不当使用 std::shared_ptr 可能导致循环引用,使对象无法释放。
常见问题:循环引用
当观察者和被观察者互相持有 shared_ptr 时,引用计数无法归零。例如:

class Observer;
class Subject {
    std::shared_ptr<Observer> obs;
};
class Observer {
    std::shared_ptr<Subject> subj;
};
上述代码中,Subject 持有 Observer 的 shared_ptr,反之亦然,形成循环。应将一方改为 std::weak_ptr 打破循环。
推荐实践
  • 使用 std::weak_ptr 存储观察者,避免持有强引用
  • 在信号触发前检查 weak_ptr.expired()
  • 确保槽函数生命周期不依赖于信号源

3.3 实际代码示例:一个看似正确却引发泄漏的类设计

问题类的设计结构
下面是一个在事件监听场景中常见的类设计,表面逻辑合理,但隐藏资源泄漏风险:

class DataProcessor {
  constructor(source) {
    this.source = source;
    this.handler = () => this.process();
    this.source.addEventListener('data', this.handler);
  }

  process() {
    console.log('Processing data...');
  }

  destroy() {
    // 缺失移除事件监听
  }
}
该类在构造时绑定事件监听,但未在 destroy 方法中调用 removeEventListener。由于事件处理器持有 this 引用,导致实例无法被垃圾回收。
泄漏成因分析
  • 事件监听器形成闭包,强引用当前实例
  • 缺少显式解绑,即使外部引用释放也无法回收
  • 频繁创建实例将导致内存持续增长
修复方式是在 destroy 中添加:
this.source.removeEventListener('data', this.handler);

第四章:检测、诊断与解除循环引用的有效策略

4.1 利用weak_ptr打破循环:从理论到重构实战

在C++智能指针使用中,shared_ptr的循环引用常导致内存泄漏。当两个对象相互持有对方的shared_ptr时,引用计数无法归零,析构函数不会被调用。
循环引用的典型场景
struct Node {
    std::shared_ptr<Node> parent;
    std::shared_ptr<Node> child;
};
// parent与child互相引用,形成循环,资源无法释放
上述代码中,即使作用域结束,引用计数仍大于0,造成内存泄漏。
使用weak_ptr打破循环
将双向关系中的一方改为weak_ptr,避免增加引用计数:
struct Node {
    std::weak_ptr<Node> parent;  // 不增加引用计数
    std::shared_ptr<Node> child;
};
weak_ptr作为观察者,可通过lock()获取临时shared_ptr,安全访问目标对象。
  • 适用于父子结构、观察者模式等双向关联场景
  • 降低内存泄漏风险,提升资源管理效率

4.2 使用静态分析工具和运行时日志定位引用环

在 Go 语言开发中,引用环(Reference Cycle)常导致内存泄漏。通过静态分析工具可提前发现潜在问题。
常用静态分析工具
  • go vet:内置工具,检测代码中常见错误;
  • staticcheck:更强大的第三方分析器,支持复杂模式识别。
运行时日志辅助排查
结合 pprof 和日志输出,观察对象生命周期:
import "runtime/pprof"

// 在关键位置触发堆快照
pprof.WriteHeapProfile(file)
该代码用于生成当前堆状态快照,通过对比不同时间点的对象引用链,可精确定位无法被回收的环状引用结构。
典型场景示例
表格展示分析流程:
步骤操作
1使用 staticcheck 扫描源码
2注入 pprof 堆采样点
3分析 profile 数据中的持久对象

4.3 RAII与智能指针设计原则的最佳实践总结

资源获取即初始化(RAII)的核心思想
RAII 是 C++ 中管理资源的关键机制,其核心在于将资源的生命周期绑定到对象的生命周期上。当对象构造时获取资源,析构时自动释放,确保异常安全和资源不泄漏。
智能指针的选择策略
  • std::unique_ptr:独占所有权,轻量高效,适用于单一所有者场景;
  • std::shared_ptr:共享所有权,配合引用计数使用,适用于多所有者;
  • std::weak_ptr:打破循环引用,辅助 shared_ptr 避免内存泄漏。
避免常见陷阱
std::shared_ptr<Resource> ptr1 = std::make_shared<Resource>();
std::weak_ptr<Resource> ptr2 = ptr1; // 使用 weak_ptr 观察资源
// ... 在需要时通过 ptr2.lock() 获取临时 shared_ptr
上述代码通过 weak_ptr 避免循环引用导致的内存泄漏。调用 lock() 可安全检查资源是否仍存活,是管理长期观察者的最佳实践。

4.4 模拟调试:通过GDB观察引用计数变化轨迹

在排查资源生命周期问题时,引用计数的动态变化是关键线索。通过GDB可实时监控对象引用的增减过程,精准定位泄露或过早释放问题。
编译与调试准备
确保程序以调试模式编译,保留符号信息:
gcc -g -O0 ref_count_demo.c -o ref_count_demo
该命令关闭优化并嵌入调试符号,便于GDB追踪变量。
设置观察点
假设引用计数字段为 ref_count,可在GDB中设置硬件观察点:
gdb ./ref_count_demo
(gdb) break object_create
(gdb) run
(gdb) watch obj->ref_count
每次引用计数修改时,GDB将中断并显示调用栈,清晰呈现变更路径。
  • 使用 backtrace 查看函数调用链
  • 结合 step 和 print 验证参数合法性

第五章:总结与防范内存泄漏的设计哲学

构建资源生命周期管理机制
在大型系统中,对象的创建与销毁必须遵循明确的生命周期协议。以 Go 语言为例,可通过显式调用关闭函数确保资源释放:

conn, err := net.Dial("tcp", "example.com:80")
if err != nil {
    log.Fatal(err)
}
defer conn.Close() // 确保连接在函数退出时关闭

// 使用 conn 进行通信
_, err = conn.Write([]byte("GET / HTTP/1.0\r\n\r\n"))
if err != nil {
    log.Printf("write error: %v", err)
}
// defer 自动触发 Close,防止文件描述符泄漏
采用引用监控与自动回收策略
现代运行时环境普遍依赖垃圾回收,但开发者仍需警惕强引用导致的对象滞留。常见场景包括未清理的事件监听器或缓存映射。
  • 避免在全局 map 中无限制存储对象引用
  • 使用弱引用(如 Java 的 WeakHashMap)管理缓存
  • 定期通过分析工具(如 pprof、Valgrind)检测堆内存分布
设计可预测的资源释放接口
模式适用场景风险控制
RAII(资源获取即初始化)C++、Rust析构函数自动释放资源
Context 取消传播Go 并发请求链路超时或取消时级联关闭资源
建立持续监控与自动化检测流程
[监控流程] 应用启动 → 启用内存 Profiling → 定期采集堆快照 → 差异比对 → 异常增长报警 → 自动生成分析报告
C语言内存泄漏的常见情况及解决方案 (Memory Leak)是指程序在申请内存后,无法释放已申请的内存空间,一次小的内存泄漏可能没什么影响,但长期或频繁发生会占用大量内存,影响系统性能甚至引发系统崩溃,造成系统资源的浪费。比如C++ 11引入了智能指针,它可以自动管理内存,当智能指针离开作用域时,它会自动释放所管理的内存。在C/C++中,我们使用new/malloc等函数来申请内存,如果忘记使用delete/free来释放内存,就会造成内存泄漏。因此,无论使用哪种编程语言,程序员都需要对内存管理保持警惕,以避免产生内存泄漏。 阅读详情

相关推荐

weak_ptr的作用及应用场景——shared_ptr的循环引用问题

weak_ptr 是为了辅助shared_ptr而引入的一种智能指针,它存在的意义就是协助shared_ptr更好的完成工作,我们可以把它比做成一个秘书或助理。 weak_ptr的构造和析构并不会改变引用计数的大小,它可以由一个shared_ptr或weak_ptr的对象构造获得。它没有对“*”和“->”的重载,但可以使用lock获得一个可用的shared_ptr对象。 当面试官问到weak_

LLZK_的博客 5622

一篇文章带你详细了解C++智能指针

C++引入智能指针的主要目的是为了解决手动管理内存的问题,提高程序的健壮性和可维护性。在C++中,内存管理由程序员手动完成,包括内存的分配和释放。手动管理内存可能导致一些常见的问题,如内存泄漏、释放已经释放的内存(二次释放)、野指针等。

立志做一个高产且细节博主 1465

如何使用weak_ptr解决shared_ptr解决循环引用问题

为什么会造成循环引用问题: 首先来看一段代码: 在该带码的运行结果中可以看到引用计数都是2,在分别调用析构函数之后它们 的引用计数都变成1,但是只有当引用计数都变成0的时候才会真正销毁资源,因此在此代码中发生了内存泄漏。 为什么引用计数会变成2: 首先在声明sp1和sp2时它们的引用计数都变成1,然后分别给其中管理的指针进行赋值的时候,引用计数又会进行加1,这样在最后在析构资源就会造成了循环引用,这也就是循环引用问题,也就是shared_ptr中的缺陷。 接下来描述如何解决这个问题: 这个.

liuming 2011

shared_ptr产生内存泄漏的场景

使用 shared_ptr 可以帮助管理动态分配的内存,它使用引用计数的方式来跟踪共享对象的引用数量,当引用计数为零时,会自动释放内存。

sinat_31608641的博客 2539

ENVI新手避坑指南:手把手教你搞定遥感影像的坐标系转换(附ArcGIS对比)

本文详细解析ENVI与ArcGIS在遥感影像坐标系转换中的关键差异与实战技巧,特别针对新手常见问题提供避坑指南。从基础概念到高级操作,涵盖定义投影、UTM转换等核心步骤,并对比两种软件的处理精度与效率,帮助用户高效完成遥感影像处理任务。

weixin_42531925的博客 378

避坑指南:Unity新版InputSystem在移动端的5个常见问题及解决方案

本文针对Unity新版InputSystem在移动端开发中的常见问题,提供了5个关键解决方案,包括虚拟摇杆灵敏度调节、多点触控冲突处理、按钮反馈延迟优化、手势识别与陀螺仪数据融合以及Android/iOS平台差异处理。这些实战经验帮助开发者高效解决触控适配难题,提升移动游戏体验。

soda5的博客 405

shared_ptr-循环引用问题

前文我们阐述了智能指针的思想和进行了简单的实现,当然最后提出了shared_ptr引用计数的线程安全问题,最简单的方式就是通过加锁来进行实现。智能指针内容:C++ 智能指针原理及简单实现那解决了引用计数的问题就可以了吗?其实不然,要使shared_ptr是线程安全的,就还得解决shared_ptr的循环引用的问题。编译环境:vs2013C++11和boost中智能指针的关系(1) C++ 98 中产生了第一个智能指针auto_ptr。

m0_69597277的博客 1304

pytorch多层感知机实现假钞识别(完整项目构建)

目录1 项目构建2 超参数设置 config.py3 数据集预处理 preprocess.py4 数据集类构建 dataset_banknote.py5 模型构建 model.py6 训练trainer.py6.1 查看损失曲线7 在测试集上运行 inference.py 1 项目构建 构建项目文件夹Banknote,以及子文件夹与py文件。 名称 作用 data目录 存放原始数据与预处理后切分为训练集、验证机、测试集的数据 log目录 存放训练过程中保存的指标,如损失、精确度等

Demon_LMMan的博客 2027

(C++) share_ptr 之循环引用

unique_ptrshared_ptrweak_ptr都是内存管理中的非常重要的一部分动态内存管理 - cppreference.com。其中shared_ptr在实际应用中具有非常广泛的应用。而由于其较unique_ptr的功能多,有引用计数的概念。导致存在一个名为循环引用的问题。这是一个非常经典的坑。但解决方案也不是很复杂。下面来一起看看吧。

cuber-lotus的博客 2975

Geant4学习——入门(基本概念、Geant4工具包的结构、强制类、可选类)

Geant4是由欧洲核子研究组织基于C++面向对象技术开发的蒙特卡罗应用软件包,用于模拟粒子在物质中输运的物理过程。由于具有良好的通用性和扩展能力,Geant4在涉及微观粒子与物质相互作用的诸多领域获得了广泛应用。 第一部分 Geant4的基本概念 HEP中的模拟是“虚拟现实”。仿真既可用于在研发阶段帮助设计探测器,又可用于物理研究中了解探测器的响应。为了创建这样的虚拟现实,我们需要对粒子间的相互作用,几何形状和材料进行建模,以便将基本粒子传播到检测器中。我们还需要描述检测器生成原始数据的灵敏度。 Gea

M_M-铭的博客 2万+

【论文学习】《Fully-Convolutional Siamese Networks for Object Tracking》2016年SiamFC 全卷积孪生网络用于目标跟踪

在这项工作中,我们脱离了跟踪中采用的传统在线学习方法,并展示了一种专注于在离线阶段学习强嵌入的替代方法。与在分类设置中的使用不同,我们证明,对于跟踪应用,孪生全卷积深度网络能够更有效地使用可用数据。这不仅反映在测试时,通过执行有效的空间搜索,也反映在训练时,其中每个子窗口都有效地代表一个有用的样本,而几乎没有额外的成本。实验表明,深度嵌入为在线跟踪器提供了自然丰富的特征来源,并使简单的测试时策略表现良好。我们相信这种方法是对更复杂的在线跟踪方法的补充,并期望未来的工作能够更彻底地探索这种关系。

SkyLeopard的博客 2419

【C++入门到精通】智能指针 shared_ptr循环引用 | weak_ptr 简介及C++模拟实现 [ C++入门 ]

这篇文章介绍了std::shared_ptr循环引用问题以及解决方案std::weak_ptr。它解释了循环引用的概念,并提供了使用示例和模拟实现方法。通过阅读这篇文章,您将了解循环引用问题以及如何使用std::weak_ptr来解决该问题。

Yawesh的博客 3344

Python 爬虫实战:在丁香医生抓取健康科普文章阅读量,普及健康知识

requests:用于发送 HTTP 请求,获取网页内容。或 lxml:用于解析 HTML 页面,提取目标数据。pandas:用于数据清洗和分析。matplotlib和seaborn:用于数据可视化。通过本项目,我们实现了以下目标:使用 Python 爬虫抓取丁香医生的健康科普文章阅读量。对数据进行清洗和分析,找出热门文章。通过可视化展示数据,并普及健康知识。

u014481728的博客 1567

【C++】weak_ptr和shared_ptr循环引用问题

shared_ptr⼤多数情况下管理资源⾮常合适,⽀持RAII,也⽀持拷⻉。但是在循环引⽤的场景下会导致资源没得到释放而内存泄漏,所以我们要认识循环引⽤的场景和资源没释放的原因,并且学会使⽤weak_ptr解决这种问题。

2402_82757055的博客 1161

微信小程序——01开发前的准备和开发工具

微信小程序——01开发前的准备和开发工具

总裁余(余登武)博客 1万+

uniapp - 实现手机端H5网页直播功能效果,拿到后端推流地址或播放资源后进行前端的流畅播放和画面展示功能,uniapp实时推流/拉流直播系统详细教程(提供完整示例代码,一键复制开箱即用!)

uniapp,h5网页,手机端H5网页,uniapp h5直播功能页面,uniapp直播实时推送显示,uniapp h5直播怎么做,怎么使用uniapp去实现移动端手机H5直播,h5 vue+uniapp怎么做直播,uniapp中使用videojs构建H5直播播放器,uniappH5端怎么实现直播推流,uniapp如何实现直播,直播聊天功能,h5平台端直播用什么插件,uniapp手机网页直播用什么组件插件播放器,uniapp手机H5直播播放器详细教程,直播项目,怎么使用vue+uniapp怎么做H5实时直播

✅ 精选推荐文章 8792

C++ 浅谈之智能指针 shared_ptr 循环引用

智能指针 shared_ptr 循环引用

优质后端技术知识记录 1523

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

shared_ptr造成的循环引用&&解决方法和原理(弱引用&&强引用)

内存泄漏及浪费都是每个程序员非常忌讳的事情,但是稍有不慎就会造成不可弥补的损失,这里就这能指针sheard_ptr造成的循环引用及造成循环引用的原因我给大家给出了详细的图解及举例说明,同时也提供了避免这种循环引用的解决办法,就针对弱引用这一点做出了详细的解释,就针对shared_ptr和weak_ptr这两种智能指针的作用和用法也相加说明使得读者可以从代码及图例两方面对循环引用及解决办法有更深的认识。

yc2zgh1314的博客 1万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Shared_Ptr相互引用导致的内存泄漏

循环引用: 引用计数是一种便利的内存管理机制,但它有一个很大的缺点,那就是不能管理循环引用的对象。 例如: class B; class A { public: A() { std::cout << "A()" << std::endl; } ~A() { std::cout << "~A()" << std::endl; } p...

独家丶 5425

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

【内存泄漏元凶曝光】:shared_ptr循环引用的4种检测与修复方法

解决C++内存泄漏难题,深入剖析智能指针shared_ptr循环引用问题。涵盖使用weak_ptr破环、静态分析工具检测、手动断环等4种实用方法,适用于树形结构、观察者模式等场景。有效提升资源管理安全性,值得收藏。

CodeTrick的博客 910

浅谈shared_ptr与循环引用问题

前面对于智能指针已经大致的提过了,但是关于shared_ptr上一篇文章没有仔细分析,这里把它单独拎出来理一理。 前面已经提过由于scoped_ptr(unique_ptr)无法解决让多个对象管理同一块空间的情况,标准库中又追加引用了shared_ptr,而我们的shared_ptr是参考了string类当中的引用计数这个巧妙的方法来解决多个对象管理同一块空间的问题的,而且除此之外我们这里的模拟实现还要考虑跟多一点,就是加入删除器的部分,以适用不同的指针。

chenkaixin_1024的博客 6160

shared_ptr循环引用导致内存泄漏?90%开发者忽略的细节

解决C++智能指针内存泄漏难题,深入剖析shared_ptr循环引用成因与破解方法。涵盖weak_ptr破环技巧及典型应用场景,提升资源管理效率,避免程序崩溃。掌握核心机制,值得收藏。

SimProceed的博客 882

智能指针进阶:从shared_ptr到weak_ptr,破解循环引用的终极方案

摘要:本文深入解析C++中shared_ptr循环引用的成因及解决方案。通过介绍shared_ptr控制块结构和引用计数机制,分析双向链表等场景下循环引用导致的内存泄漏问题。重点探讨weak_ptr如何作为"弱观察者"打破循环,并详细讲解std::enable_shared_from_this正确获取this指针shared_ptr的方法。最后给出智能指针使用的三条安全法则:用weak_ptr避免循环引用、安全获取this指针、理解控制块原理。(148字)

huahua8088的博客 990

shared_ptr创建方式以及循环引用问题

shared_ptr 是 C++ 标准库提供的智能指针,用于管理动态分配的对象,通过引用计数实现资源的自动释放。它是现代 C++ 中避免内存泄漏的核心工具之一。

2301_78992766的博客 945

std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题

在std::shared_ptr被引入之前,C++标准库中实现的用于管理资源的智能指针只有std::auto_ptr一个而已。std::auto_ptr的作用非常有限,因为它存在被管理资源的所有权转移问题。这导致多个std::auto_ptr类型的局部变量不能共享同一个资源,这个问题是非常严重的哦。因为,我个人觉得,智能指针内存管理要解决的根本问题是:一个堆对象(或则资源,比如文件句柄)在被多个对

LESS IS MORE 3万+

shared_ptr 循环引用问题以及解决办法

栗子 #include <iostream> #include <memory> class CB; class CA { public: CA() { std::cout << "CA() called! " << std::endl; } ~CA() { std::cout << "~CA() called! "...

布袋和尚 1617
上一篇: C++模板友元陷阱大盘点:3个常见错误及规避策略
下一篇: shared_ptr陷阱频发?weak_ptr观测技巧让你避开90%的内存泄漏问题
普通网友
博客等级 码龄3年 606粉丝 2892原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值