一个跨平台的 C++ 内存泄漏检测器(转载)

2023-05-16

一个跨平台的 C++ 内存泄漏检测器

吴咏炜( adah@netstd.com)
2004 年 3 月
 
        内存泄漏对于C/C++程序员来说也可以算作是个永恒的话题了吧。在Windows下,MFC的一个很有用的功能就是能在程序运行结束时报告是否发生了内存泄漏。在Linux下,相对来说就没有那么容易使用的解决方案了:像mpatrol之类的现有工具,易用性、附加开销和性能都不是很理想。本文实现一个极易于使用、跨平台的C++内存泄漏检测器。并对相关的技术问题作一下探讨。

基本使用

对于下面这样的一个简单程序test.cpp:
int main()
{
       int* p1 = new int;
       char* p2 = new char[10];
       return 0;
}
 
我们的基本需求当然是对于该程序报告存在两处内存泄漏。要做到这点的话,非常简单,只要把debug_new.cpp也编译、链接进去就可以了。在Linux下,我们使用:
g++ test.cpp debug_new.cpp -o test
 
输出结果如下所示:
Leaked object at 0x805e438 (size 10, <Unknown>:0)
Leaked object at 0x805e410 (size 4, <Unknown>:0)
 
如果我们需要更清晰的报告,也很简单,在test.cpp开头加一行
#include "debug_new.h"
 
即可。添加该行后的输出如下
Leaked object at 0x805e438 (size 10, test.cpp:5)
Leaked object at 0x805e410 (size 4, test.cpp:4)
非常简单!

背景知识

在new/delete操作中,C++为用户产生了对operator new和operator delete的调用。这是用户不能改变的。operator new和operator delete的原型如下所示:
 
void *operator new(size_t) throw(std::bad_alloc);
void *operator new[](size_t) throw(std::bad_alloc);
void operator delete(void*) throw();
void operator delete[](void*) throw();
 
对于"new int",编译器会产生一个调用"operator new(sizeof(int))",而对于"new char[10]",编译器会产生"operator new[](sizeof(char) * 10)"(如果new后面跟的是一个类名的话,当然还要调用该类的构造函数)。类似地,对于"delete ptr"和"delete[] ptr",编译器会产生"operator delete(ptr)"调用和"operator delete[](ptr)"调用(如果ptr的类型是指向对象的指针的话,那在operator delete之前还要调用对象的析构函数)。当用户没有提供这些操作符时,编译系统自动提供其定义;而当用户自己提供了这些操作符时,就覆盖了编译系统提供的版本,从而可获得对动态内存分配操作的精确跟踪和控制。
同时,我们还可以使用placement new操作符来调整operator new的行为。所谓placement new,是指带有附加参数的new操作符,比如,当我们提供了一个原型为
void* operator new(size_t size, const char* file, int line);
的操作符时,我们就可以使用"new("hello", 123) int"来产生一个调用"operator new(sizeof(int), "hello", 123)"。这可以是相当灵活的。又如,C++标准要求编译器提供的一个placement new操作符是
void* operator new(size_t size, const std::nothrow_t&);
其中,nothrow_t通常是一个空结构(定义为"struct nothrow_t {};"),其唯一目的是提供编译器一个可根据重载规则识别具体调用的类型。用户一般简单地使用"new(std::nothrow) 类型"(nothrow是一个nothrow_t类型的常量)来调用这个placement new操作符。它与标准new的区别是,new在分配内存失败时会抛出异常,而"new(std::nothrow)"在分配内存失败时会返回一个空指针。
 
要注意的是,没有对应的"delete(std::nothrow) ptr"的语法;不过后文会提到另一个相关问题。
 
要进一步了解以上关于C++语言特性的信息,请参阅[Stroustrup1997],特别是6.2.6、10.4.11、15.6、19.4.5和B.3.4节。这些C++语言特性是理解本实现的关键。

检测原理

和其它一些内存泄漏检测的方式类似,debug_new中提供了operator new重载,并使用了宏在用户程序中进行替换。debug_new.h中的相关部分如下:
void* operator new(size_t size, const char* file, int line);
void* operator new[](size_t size, const char* file, int line);
#define new DEBUG_NEW
#define DEBUG_NEW new(__FILE__, __LINE__)
 
拿上面加入debug_new.h包含后的test.cpp来说,"new char[10]"在预处理后会变成"new("test.cpp", 4) char[10]",编译器会据此产生一个"operator new[](sizeof(char) * 10, "test.cpp", 4)"调用。通过在debug_new.cpp中自定义"operator new(size_t, const char*, int)"和"operator delete(void*)"(以及"operator new[]…"和"operator delete[]…";为避免行文累赘,以下不特别指出,说到operator new和operator delete均同时包含数组版本),我可以跟踪所有的内存分配调用,并在指定的检查点上对不匹配的new和delete操作进行报警。实现可以相当简单,用map记录所有分配的内存指针就可以了:new时往map里加一个指针及其对应的信息,delete时删除指针及对应的信息;delete时如果map里不存在该指针为错误删除;程序退出时如果map里还存在未删除的指针则说明有内存泄漏。
不过,如果不包含debug_new.h,这种方法就起不了作用了。不仅如此,部分文件包含debug_new.h,部分不包含debug_new.h都是不可行的。因为虽然我们使用了两种不同的operator new --"operator new(size_t, const char*, int)"和"operator new(size_t)"-- 但可用的"operator delete"还是只有一种!使用我们自定义的"operator delete",当我们删除由"operator new(size_t)"分配的指针时,程序将认为被删除的是一个非法指针!我们处于一个两难境地:要么对这种情况产生误报,要么对重复删除同一指针两次不予报警:都不是可接受的良好行为。
看来,自定义全局"operator new(size_t)"也是不可避免的了。在debug_new中,我是这样做的:
void* operator new(size_t size)
{
       return operator new(size, "<Unknown>", 0);
}
但前面描述的方式去实现内存泄漏检测器,在某些C++的实现中(如GCC 2.95.3中带的SGI STL)工作正常,但在另外一些实现中会莫名其妙地崩溃。原因也不复杂,SGI STL使用了内存池,一次分配一大片内存,因而使利用map成为可能;但在其他的实现可能没这样做,在map中添加数据会调用operator new,而operator new会在map中添加数据,从而构成一个死循环,导致内存溢出,应用程序立即崩溃。因此,我们不得不停止使用方便的STL模板,而使用手工构建的数据结构:
struct new_ptr_list_t
{
       new_ptr_list_t*             next;
       const char*                  file;
       int                                line;
       size_t                           size;
};
我最初的实现方法就是每次在使用new分配内存时,调用malloc多分配 sizeof(new_ptr_list_t) 个字节,把分配的内存全部串成一个一个链表(利用next字段),把文件名、行号、对象大小信息分别存入file、line和size字段中,然后返回(malloc返回的指针 + sizeof(new_ptr_list_t))。在delete时,则在链表中搜索,如果找到的话((char*)链表指针 + sizeof(new_ptr_list_t) == 待释放的指针),则调整链表、释放内存,找不到的话报告删除非法指针并abort。
至于自动检测内存泄漏,我的做法是生成一个静态全局对象(根据C++的对象生命期,在程序初始化时会调用该对象的构造函数,在其退出时会调用该对象的析构函数),在其析构函数中调用检测内存泄漏的函数。用户手工调用内存泄漏检测函数当然也是可以的。
基本实现大体就是如此。

可用性改进

上述方案最初工作得相当好,直到我开始创建大量的对象为止。由于每次delete时需要在链表中进行搜索,平均搜索次数为(链表长度/2),程序很快就慢得像乌龟爬。虽说只是用于调试,速度太慢也是不能接受的。因此,我做了一个小更改,把指向链表头部的new_ptr_list改成了一个数组,一个对象指针放在哪一个链表中则由它的哈希值决定。--用户可以更改宏DEBUG_NEW_HASH和DEBUG_NEW_HASHTABLESIZE的定义来调整debug_new的行为。他们的当前值是我测试下来比较满意的定义。
使用中我们发现,在某些特殊情况下(请直接参看debug_new.cpp中关于DEBUG_NEW_FILENAME_LEN部分的注释),文件名指针会失效。因此,目前的debug_new的缺省行为会复制文件名的头20个字符,而不只是存储文件名的指针。另外,请注意原先new_ptr_list_t的长度为16字节,现在是32字节,都能保证在通常情况下内存对齐。
此外,为了允许程序能和 new(std::nothrow) 一起工作,我也重载了operator new(size_t, const std::nothrow_t&) throw();不然的话,debug_new会认为对应于 new(nothrow) 的delete调用删除的是一个非法指针。由于debug_new不抛出异常(内存不足时程序直接报警退出),所以这一重载的操作只不过是调用 operator new(size_t) 而已。这就不用多说了。
前面已经提到,要得到精确的内存泄漏检测报告,可以在文件开头包含"debug_new.h"。我的惯常做法可以用作参考:
#ifdef _DEBUG
#include "debug_new.h"
#endif
包含的位置应当尽可能早,除非跟系统的头文件(典型情况是STL的头文件)发生了冲突。在某些情况下,可能会不希望debug_new重定义new,这时可以在包含debug_new.h之前定义DEBUG_NEW_NO_NEW_REDEFINITION,这样的话,在用户应用程序中应使用debug_new来代替new(顺便提一句,没有定义DEBUG_NEW_NO_NEW_REDEFINITION时也可以使用debug_new代替new)。在源文件中也许就该这样写:
 
#ifdef _DEBUG
#define DEBUG_NEW_NO_NEW_REDEFINITION
#include "debug_new.h"
#else
#define debug_new new
#endif
并在需要追踪内存分配的时候全部使用debug_new(考虑使用全局替换)。
用户可以选择定义DEBUG_NEW_EMULATE_MALLOC,这样debug_new.h会使用debug_new和delete来模拟malloc和free操作,使得用户程序中的malloc和free操作也可以被跟踪。在使用某些编译器的时候(如Digital Mars C++ Compiler 8.29和Borland C++ Compiler 5.5.1),用户必须定义NO_PLACEMENT_DELETE,否则编译无法通过。用户还可以使用两个全局布尔量来调整debug_new的行为:new_verbose_flag,缺省为false,定义为true时能在每次new/delete时向标准错误输出显示跟踪信息;new_autocheck_flag,缺省为true,即在程序退出时自动调用check_leaks检查内存泄漏,改为false的话用户必须手工调用check_leaks来检查内存泄漏。
需要注意的一点是,由于自动调用check_leaks是在debug_new.cpp中的静态对象析构时,因此不能保证用户的全局对象的析构操作发生在check_leaks调用之前。对于Windows上的MSVC,我使用了"#pragma init_seg(lib)"来调整对象分配释放的顺序,但很遗憾,我不知道在其他的一些编译器中(特别是,我没能成功地在GCC中解决这一问题)怎么做到这一点。为了减少误报警,我采取的方式是在自动调用了check_leaks之后设new_verbose_flag为true;这样,就算误报告了内存泄漏,随后的delete操作还是会被打印显示出来。只要泄漏报告和delete报告的内容一致,我们仍可以判断出没有发生内存泄漏。
Debug_new也能检测对同一指针重复调用delete(或delete无效指针)的错误。程序将显示错误的指针值,并强制调用abort退出。
还有一个问题是异常处理。这值得用专门的一节来进行说明。

构造函数中的异常

我们看一下以下的简单程序示例:
#include <stdexcept>
#include <stdio.h>
 
void* operator new(size_t size, int line)
{
       printf("Allocate %u bytes on line %d//n", size, line);
       return operator new(size);
}
 
class Obj {
public:
       Obj(int n);
private:
       int _n;
};
 
Obj::Obj(int n) : _n(n)
{
       if (n == 0) {
              throw std::runtime_error("0 not allowed");
       }
}
 
int main()
{
       try {
              Obj* p = new(__LINE__) Obj(0);
              delete p;
       } catch (const std::runtime_error& e) {
              printf("Exception: %s//n", e.what());
       }
}
看出代码中有什么问题了吗?实际上,如果我们用MSVC编译的话,编译器的警告信息已经告诉我们发生了什么:
test.cpp(27) : warning C4291: 'void *__cdecl operator new(unsigned int,int)' :
no matching operator delete found; memory will not be freed if initialization throws an exception
好,把debug_new.cpp链接进去。运行结果如下:
 
Allocate 4 bytes on line 27 Exception: 0 not allowed Leaked object at 00342BE8 (size 4, <Unknown>:0)
 
啊哦,内存泄漏了不是!
 
当然,这种情况并非很常见。可是,随着对象越来越复杂,谁能够保证一个对象的子对象的构造函数或者一个对象在构造函数中调用的所有函数都不会抛出异常?并且,解决该问题的方法并不复杂,只是需要编译器对 C++ 标准有较好支持,允许用户定义 placement delete 算符([C++1998],5.3.4节;网上可以找到1996年的标准草案,比如下面的网址 http://www.comnets.rwth-aachen.de/doc/c++std/expr.html#expr.new)。在我测试的编译器中,GCC(2.95.3或更高版本,Linux/Windows)和MSVC(6.0或更高版本)没有问题,而Borland C++ Compiler 5.5.1和Digital Mars C++ Compiler(到v8.38为止的所有版本)则不支持该项特性。在上面的例子中,如果编译器支持的话,我们就需要声明并实现 operator delete(void*, int) 来回收new分配的内存。编译器不支持的话,需要使用宏让编译器忽略相关的声明和实现。如果要让debug_new在Borland C++ Compiler 5.5.1或Digital Mars C++ Compiler下编译的话,用户必须定义宏NO_PLACEMENT_DELETE;当然,用户得自己注意小心构造函数中抛出异常这个问题了。

方案比较

IBM developerWorks上刊载了洪琨先生设计实现的一个Linux上的内存泄漏检测方法([洪琨2003])。我的方案与其相比,主要区别如下:
 
优点:
Ÿ           跨平台:只使用标准函数,并且在GCC 2.95.3/3.2(Linux/Windows)、MSVC 6、Digital Mars C++ 8.29、Borland C++ 5.5.1等多个编译器下调试通过。(虽然Linux是我的主要开发平台,但我发现,有时候能在Windows下编译运行代码还是非常方便的。)
Ÿ           易用性:由于重载了operator new(size_t)--洪琨先生只重载了operator new(size_t, const char*, int)--即使不包含我的头文件也能检测内存泄漏;程序退出时能自动检测内存泄漏;可以检测用户程序(不包括系统/库文件)中malloc/free产生的内存泄漏。
灵活性:有多个灵活的可配置项,可使用宏定义进行编译时选择。
可重入性:不使用全局变量,没有嵌套delete问题。
异常安全性:在编译器支持的情况下,能够处理构造函数中抛出的异常而不发生内存泄漏。
缺点:
单线程模型:跨平台的多线程实现较为麻烦,根据项目的实际需要,也为了代码清晰简单起见,我的方案不是线程安全的;换句话说,如果多个线程中同时进行new或delete操作的话,后果未定义。
未实现运行中内存泄漏检测报告机制:没有遇到这个需求J;不过,如果要手工调用check_leaks函数实现的话也不困难,只是跨平台性就有点问题了。
不能检测带 [] 算符和不带 [] 算符混用的不匹配:主要也是需求问题(如果要修改实现的话并不困难)。
不能在错误的delete调用时显示文件名和行号:应该不是大问题;由于我重载了operator new(size_t),可以保证delete出错时程序必然有问题,因而我不只是显示警告信息,而且会强制程序abort,可以通过跟踪程序、检查abort时程序的调用栈知道问题出在哪儿。
另外,现在已存在不少商业和Open Source的内存泄漏检测器,本文不打算一一再做比较。Debug_new与它们相比,功能上总的来说仍较弱,但是,其良好的易用性和跨平台性、低廉的附加开销还是具有很大优势的。

总结和讨论

以上段落基本上已经说明了debug_new的主要特点。下面做一个小小的总结。
重载的算符:
operator new(size_t, const char*, int)
operator new[](size_t, const char*, int)
operator new(size_t)
operator new[](size_t)
operator new(size_t, const std::nothrow_t&)
operator new[](size_t, const std::nothrow_t&)
operator delete(void*)
operator delete[](void*)
operator delete(void*, const char*, int)
operator delete[](void*, const char*, int)
operator delete(void*, const std::nothrow_t&)
operator delete[](void*, const std::nothrow_t&)
提供的函数:
check_leaks()
检查是否发生内存泄漏
提供的全局变量
new_verbose_flag
是否在new和delete时"罗嗦"地显示信息
new_autocheck_flag
是否在程序退出是自动检测一次内存泄漏

可重定义的宏:

NO_PLACEMENT_DELETE
假设编译器不支持placement delete(全局有效)
DEBUG_NEW_NO_NEW_REDEFINITION
不重定义new,假设用户会自己使用debug_new(包含debug_new.h时有效)
DEBUG_NEW_EMULATE_MALLOC
重定义malloc/free,使用new/delete进行模拟(包含debug_new.h时有效)
DEBUG_NEW_HASH
改变内存块链表哈希值的算法(编译debug_new.cpp时有效)
DEBUG_NEW_HASHTABLE_SIZE
改变内存块链表哈希桶的大小(编译debug_new.cpp时有效)
DEBUG_NEW_FILENAME_LEN
如果在分配内存时复制文件名的话,保留的文件名长度;为0时则自动定义
DEBUG_NEW_NO_FILENAME_COPY(编译debug_new.cpp时有效;参见文件中的注释)
DEBUG_NEW_NO_FILENAME_COPY
分配内存时不进行文件名复制,而只是保存其指针;效率较高(编译debug_new.cpp时有效;参见文件中的注释)
我本人认为,debug_new目前的一个主要缺陷是不支持多线程。对于某一特定平台,要加入多线程支持并不困难,难就难在通用上(当然,条件编译是一个办法,虽然不够优雅)。等到C++标准中包含线程模型时,这个问题也许能比较完美地解决吧。另一个办法是使用像boost这样的程序库中的线程封装类,不过,这又会增加对其它库的依赖性--毕竟boost并不是C++标准的一部分。如果项目本身并不用boost,单为了这一个目的使用另外一个程序库似乎并不值得。因此,我自己暂时就不做这进一步的改进了。
另外一个可能的修改是保留标准operator new的异常行为,使其在内存不足的情况下抛出异常(普通情况)或是返回NULL(nothrow情况),而不是像现在一样终止程序运行(参见debug_new.cpp的源代码)。这一做法的难度主要在于后者:我没想出什么方法,可以保留 new(nothrow) 的语法,同时能够报告文件名和行号,并且还能够使用普通的new。不过,如果不使用标准语法,一律使用debug_new和debug_new_nothrow的话,那还是非常容易实现的。
如果大家有改进意见或其它想法的话,欢迎来信讨论。
debug_new 的源代码目前可以在 dbg_new.zip处下载。
在这篇文章的写完之后,我终于还是实现了一个线程安全的版本。该版本使用了一个轻量级的跨平台互斥体类fast_mutex(目前支持Win32和POSIX线程,在使用GCC(Linux/MinGW)、MSVC时能通过命令行参数自动检测线程类型)。有兴趣的话可在 http://mywebpage.netscape.com/yongweiwu/dbg_new.tgz下载。

参考资料

[C++1998] ISO/IEC 14882. Programming Languages-C++, 1st Edition. International Standardization Organization, International Electrotechnical Commission, American National Standards Institute, and Information Technology Industry Council, 1998
[Stroustrup1997] Bjarne Stroustrup. The C++ Programming Language, 3rd Edition. Addison-Wesley, 1997
[洪琨2003] 洪琨。 《如何在 linux 下检测内存泄漏》,IBM developerWorks 中国网站。
 
关于作者
吴咏炜,目前在Linux上从事高性能入侵检测系统的研发。对于开发跨平台、高性能、可重用的C++代码有着浓厚的兴趣。 adah@sh163.net可以跟他联系。
 
 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一个跨平台的 C++ 内存泄漏检测器(转载) 的相关文章

  • C++中的exit函数

    描述 xff1a 用来立即中止当前程序的执行 xff0c 并将一个整数返回给系统 xff0c 该整数的作用与 由mian函数返回的整数 相同 xff0c 如果是0表示程序正常退出 xff1b 如果非0表示程序异常退出 头文件 span cl
  • 将uint8_t类型的16进制字符转化转换为string字符串

    碰到一个需求 xff0c 需要把硬件读到的uint8 t类型的16进制数据转化为string类型的字符串 例如 xff0c 如果读到到的数据是一个uint8 t类型的数组uint8 t code 61 5 61 0XAA 0X01 0XE3
  • C++解析json文件

    文章目录 1 JSON文件简介 1 1 1 JSON文件的语法规则1 2 JSON值的类型 2 JSON文件解析 1 JSON文件简介 1 一个项目在设计时会存在很多参数 xff0c 比如data文件路径 外设名称与相关参数 文件储存路径等
  • YOLO-YOLOV5算法原理及网络结构整理

    文章目录 零 参考链接一 前言1 1 YOLO vs Faster R CNN 二 YOLOv1 xff08 448 448 xff09 2 1实现方法2 2 损失函数2 3 leak RELU激活函数2 4总结 三 YOLOV23 1 Y
  • ubuntu 20.04.5安装python3.9缺少ffi.h文件问题

    ubuntu 20 04 5安装python3 9缺少ffi h文件问题 OK 解决
  • 视觉SLAM基础

    文章目录 零 参考链接一 视觉SLAM面试相关问题1 李群与李代数的映射关系2 李群与李代数的扰动模型3 SIFT与SURF特征的区别4 相似变换 仿射变换 射影变换的区别5 Homograph Essential Fundamental
  • 在ubuntu18.04系统上使用ROS跑ORB-SLAM3时遇到的问题总结

    1 跑TUM VI数据集dataset corridor4 512时 xff0c 从tum vi example sh中复制对应的运行命令 xff0c 输入命令后提示找不到对应的TUM 512 yaml文件 xff0c 查找对应路径发现只有
  • ubuntu1804系统安装Realsense SDK驱动和ROS Wrapper

    文章目录 1 软件安装1 1 安装realsense SDK1 2 安装Ros Wrapper 2 打开双目的开关3关闭结构光方法1 xff1a 通过可视窗口关闭方法2 xff1a 通过修改launch文件关闭 4查看相机参数 说明 xff
  • 在使用evo进行orb-slam2轨迹评估时提示时间戳没有对齐的问题

    最近使用一个orb slam2修改版跑euroc数据集 在使用evo评估绝对轨迹误差时出现下面的报错 found no matching timestamps between CameraTrajectory txt and gt MH01
  • ORB-SLAM2论文翻译

    文章转载至泡泡机器人 转载链接 链接 摘要 ORB SLAM2是基于单目 xff0c 双目和RGB D相机的一套完整的SLAM方案 它能够实现地图重用 xff0c 回环检测和重新定位的功能 无论是在室内的小型手持设备 xff0c 还是到工厂
  • ROS使用命令行查看图像消息的宽和高

    备忘 xff1a ROS在终端使用命令行查看图像消息的宽和高 span class token comment 查看图像的宽 span rostopic span class token builtin class name echo sp
  • C++读取指定目录下的所有文件

    简介 xff1a 代码备忘 xff0c 使用C 43 43 读取指定目录下的所有文件名 xff0c 并存入vector向量 需要的头文件 span class token macro property span class token di
  • ubuntu1804进行vins-fusion算法环境搭建遇到的问题汇总

    简介 xff1a 在ubuntu1804系统搭建vins fusion环境并基于euroc数据集进行测试 xff0c 对遇到的编译报错和解决办法进行汇总 1 vins fusion算法环境搭建 报错1 Chessboard cc 20 38
  • ubuntu1804搭建svo2.0环境并跑euroc数据集

    0说明 整个SVO2 0环境搭建过程按照官网的说明进行 链接 xff1a https github com uzh rpg rpg svo pro open 开发环境是ubuntu18 04 43 ROS Melodic 1工具安装 Ins
  • 使用ceres库时报错:undefined reference to `ceres::Problem::Problem()‘

    编译cmake项目链接ceres库时名称没有写对导致报错 myCeres cpp span class token punctuation span text startup 43 0x247 span class token punctu
  • qt.qpa.plugin: Could not load the Qt platform plugin “xcb“

    运行环境 ubuntu 20 04 5 使用python3 9 由于使用qt5的同时使用了opencv导致如下报错 应该是由于调用环境不兼容导致的 需要加入如下代码问题解决 import os os environ pop 34 QT QP
  • 【Ubuntu】触摸屏旋转配置

    1 主要参考这篇文章编写配置脚本 Ubuntu18 04双屏显示触屏设置 xff0c 解决触摸点和响应位置不一致的问题 iShare 123的博客 CSDN博客 ubuntu触摸屏设置 Ubuntu18 04双屏 https blog cs
  • 红外视频——行人识别

    最近在做关于红外视频的项目 xff0c 主要是对区域入侵检测 xff0c 主要是能够对行人进行识别 xff0c 又到了瓶颈期 xff0c 所以看看论文找些灵感 xff0c 下面也主要是对看到的论文的思想及实现步骤进行总结 1 Thermal
  • Ardupilot任务调度的理解

    Ardupilot通过定时器定时调度一系列任务实现任务调度 由于Ardupilot固件有基于arduino的APM发展而来 xff0c 因此程序与arduino的形式类似 xff0c 包含一个setup xff08 xff09 函数与一个l
  • 最详细的Gmapping代码详解!详细到每一行!

    无处不在的小土 gmapping的ROS封装 gaoyichao com

随机推荐

  • 【OpenCV3】棋盘格角点检测与绘制——cv::findChessboardCorners()与cv::drawChessboardCorners()详解

    棋盘格法是摄像机标定中常用的一种方法 xff0c 在使用该方法时需要对棋盘格的角点进行检测 opencv中封装了一个专门用于棋盘格角点检测的函数即cv findChessboardCorners xff0c 同时 xff0c 也提供了一个专
  • 网络编程和并发编程面试题

    网络编程和并发编程面试题 1 简述 OSI 七层协议 一 应用层 与其它计算机进行通讯的一个应用 xff0c 它是对应应用程序的通信服务的 例如 xff0c 一个没有通信功能的字处理程序就不能执行通信的代码 xff0c 从事字处理工作的程序
  • 树莓派利用串口进行通信

    树莓派串口通信 我用的是树莓派3b 43 型号 xff0c 网上各种各样的修改方式来使得树莓派的串口可以工作 xff0c 过于混乱 xff0c 还有的教程甚至会被树莓派系统搞崩溃 xff0c 尤其是树莓派实验室那里的中文教程 xff0c 是
  • Android系统学习(六)------裁剪Android系统

    你好 xff01 这里是风筝的博客 xff0c 欢迎和我一起交流 经过前面几篇博客的编译步骤 xff0c 成功的编出了Android系统 xff0c 但是发现编出来的system img有点大了 xff0c 有差不多1 7G xff0c 怎
  • 用postman批量执行post请求数据

    今天接到一个任务 xff0c 需要在同一个url中执行83次不同的post请求 xff0c 而且需要连续执行3次 xff0c 如果一个一个点击 xff0c 岂不是不符合 xff0c 摸鱼大王的风格 xff0c 思考片刻之后 xff0c 决定
  • 使用python批量发送post请求

    usr bin env python import requests url 61 34 http 192 168 26 xxx 34 header 61 39 Connection 39 39 close 39 39 Accept 39
  • 关于A 全球大气光 atmosphere light 算法总结

    由于大气散色所用引起的光源的特性 随着距离的增大而增强 A其实为无穷远处的一个大气光源 xff0c 比如天空 xff0c 这应该不是指天空中的云而是近地天空 由于各种去雾算法不同对A的依赖可能也不相同 我看到有几种方法对在去雾算法中应用 x
  • 解决树莓派开机黑屏不显示桌面问题

    一 设备状态 xff1a 以前桌面使用正常 xff0c 通过ssh进行安装pyqt5后导致桌面开机黑屏 二 所使用设备为 xff1a 树莓派4B 43 2021 05 07 raspios buster armhf img 三 定位问题 x
  • 树莓派Linux固定多USB设备号相同厂家设备和不同设备(包括一个USB设备两个设备名称号的情况)

    目录 一 问题说明 二 解决思路 三 开干 一 问题说明 在使用USB摄像头时 xff0c 由于使用了两个摄像头 xff0c 故此在上电启动后 xff0c 设备号会发生变化 xff0c 比如设备1之前时video0 xff0c 有的时候上电
  • FreeRTOS学习笔记-流缓冲区(FreeRTOS中文官网)

    https www freertos org zh cn cmn s RTOS stream buffer API html RTOS 流缓冲区 API RTOS 流缓冲区 API 函数 xff1a xStreamBufferCreate
  • FreeRTOS学习笔记-消息缓冲区(FreeRTOS中文官网)

    RTOS消息缓冲区 API RTOS 消息缓冲区 API 函数 xff1a xMessageBufferCreate xMessageBufferCreateStatic xMessageBufferSend xMessageBufferS
  • ubuntu系统X86环境下配置TX2的ARM环境的交叉编译链

    总步骤 安装qtcreator的IDE安装aarch64 linux gnu g 43 43 交叉编译链下载Qt库的源码 xff0c 配置编译选项 xff0c 编译生成针对TX2的ARM环境的qmake工具配置qtcreator xff0c
  • ROS中Eigen库的引用

    在CmakeList txt中添加两个地方 find package Eigen REQUIRED include directories Eigen INCLUDE DIR 如果找不到Eigen xff0c 我们将第一句改成 find p
  • ROS tf使用

    1 静态tf发布 lt node pkg 61 34 tf 34 type 61 34 static transform publisher 34 name 61 34 link1 link2 broadcaster 34 args 61
  • SLAM算法配置——使用Realsense D435i结合ROS跑通ORB-SLAM2的RGB-D节点

    ORB SLAM2源地址 配置环境依赖 Pangolin xff0c OpenCV xff0c Eigen3 xff0c DBoW2 and g2o xff08 源代码里有 xff0c 不用自己装 xff09 xff0c ROS xff08
  • 代码编写及阅读规范

    阅读常识 1 C语言中在函数名或关键字前加下划线 一般情况是标识该函数或关键字是自己内部使用的 xff0c 与提供给外部的接口函数或关键字加以区分 规范 综述 C 43 43 是一门十分复杂并且威力强大的语言 xff0c 使用这门语言的时候
  • 流媒体开发之路

    其实很早之前 xff0c 就想写属于自己的博客 xff0c 大二就有了CSDN账号 xff0c 很讽刺的是 xff0c 工作几年了 xff0c 账号里面的内容竟然和小鲜肉脸一样干净 干净的让人尴尬 回顾自己的这几年的开发之路 xff0c 接
  • matlab图像处理实例详解---note

    1 直方图均衡及直方图规定化 可以优化图像的亮度及gamma效果 2 图像的标准差 当图像越清晰的时候 xff0c 图像的标准差就越大 是否可以用来做af的判定标准 作为fv的值 另外是否可以用图像的相关系数作为caf的一个trigger
  • promise限制并发请求数量

    所谓并发请求 xff0c 就是指在一个时间点多个请求同时执行 当并发的请求超过一定数量时 xff0c 会造成网络堵塞 xff0c 服务器压力大崩溃或者其他高并发问题 xff0c 此时需要限制并发请求的数量 假如等待请求接口1000个 xff
  • 一个跨平台的 C++ 内存泄漏检测器(转载)

    一个跨平台的 C 43 43 内存泄漏检测器 吴咏炜 adah 64 netstd com 2004 年 3 月 内存泄漏对于C C 43 43 程序员来说也可以算作是个永恒的话题了吧 在Windows下 xff0c MFC的一个很有用的功