内存泄漏检测工具的原理
内存泄露
一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定)内存块,使用完后必须显式释放的内存。应用程序般使用malloc,、realloc、 new等函数从堆中分配到块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。
简单地说就是申请了一块内存空间,使用完毕后没有释放掉。 它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。
常见的内存泄露方式
- 未配对
char *pt = (char *)malloc(10); //堆上申请空间,未配对free(pt)
- 丢失地址
char *pt= (char *)malloc(10);
pt= (char *)malloc(20); //覆盖了指针,导致前面10个空间的地址丢失。
- 未分级释放
#include <stdio.h>
#include <stdlib.h>
struct birth
{
int year;
int month;
int day;
};
struct student
{
char is_male;
char *name;
struct birth * bi;
};
int main()
{
struct student *pt;
pt= (struct student *)malloc(sizeof(struct student)); //堆上申请空间
pt->is_male =1;
pt->name ="wangwei";
pt->bi = (struct birth *)malloc(sizeof(struct birth)); //堆上申请空间
pt->bi->year =2000;
pt->bi->month =3;
pt->bi->day =2;
printf("%s %d \n",pt->name,pt->bi->day);
//逐级释放空间,避免内存泄漏
//pt->name 是字符串常量 不用释放
if(pt->bi!=NULL){
free(pt->bi); //先释放子空间
pt->bi=NULL;
}
free(pt); //后释放父空间
pt =NULL; //避免野指针 (操作已释放的空间)
return 0;
}
避免内存泄露的几种方式
- 显式释放内存:程序在使用动态分配的内存时,应该及时使用free函数将不再需要的内存释放掉。需要注意的是,释放的内存必须是程序动态分配的内存,而不是栈空间中的局部变量。有new就有delete,有malloc就有free,保证它们一定成对出现
- 避免重复分配内存:程序在使用动态分配的内存时,应该避免重复分配内存,特别是在循环中。如果需要多次分配内存,可以使用realloc函数重新调整内存块的大小,以减少内存碎片的产生。
- 使用智能指针:智能指针是一种自动管理内存的工具,可以避免手动释放内存的繁琐操作。智能指针会在对象不再被使用时自动释放内存,并且可以避免内存泄漏和悬空指针等问题。
- 计数法:使用new或者malloc时,让该数+1,delete或free时,该数-1,程序执行完打印这个计数,如果不为0则表示存在内存泄露
- 一定要将基类的析构函数声明为虚函数
- 对象数组的释放一定要用delete []
- 使用内存检测工具:内存检测工具可以帮助程序员检测内存泄漏和内存访问越界等问题,提高程序的健壮性和可靠性。常见的内存检测工具包括Valgrind、AddressSanitizer等。
检测工具
- Valgrind:是一款免费的内存检测工具,可以检测内存泄漏、内存访问越界、使用未初始化的内存等问题。Valgrind可以运行在Linux、Mac OS X等操作系统上,并且支持多种编程语言,包括C、C++、Java等。
- AddressSanitizer:是一款由Google开发的内存检测工具,可以检测内存泄漏、内存访问越界等问题。AddressSanitizer可以在编译时加入编译选项,支持多种编程语言,包括C、C++、Rust等。
- Electric Fence:是一款免费的内存检测工具,可以检测内存泄漏、内存访问越界等问题。Electric Fence使用了一种内存保护技术,会将分配的内存区域的前后加上一个特殊的标记,当程序访问这些标记时就会触发异常,从而帮助程序员及时发现内存问题。
- Purify:是一款商业的内存检测工具,可以检测内存泄漏、内存访问越界等问题。Purify支持多种编程语言,包括C、C++、Java等,并且可以运行在多个操作系统上,包括Linux、Windows、AIX等。
.iic驱动编写时,如果出现异常怎么排错
1. 检查硬件连接
- 确认物理连接:确保I2C总线上的所有连接(如SDA、SCL线)都正确无误,并且接触良好。
- 检查上拉电阻:I2C总线需要适当的上拉电阻,通常在1kΩ到10kΩ之间。错误的电阻值可能导致信号质量问题。
2. 验证I2C设备地址和配置
- 设备地址:确认代码中使用的设备地址与硬件设备的实际地址一致。注意7位和8位地址格式的区别。
- 配置参数:核对时钟频率、通信速率(如标准模式100kHz、快速模式400kHz)等参数是否符合设备规格。
3. 使用逻辑分析仪或示波器
- 监视信号质量:利用逻辑分析仪或示波器观察SDA和SCL线上的信号波形,检查是否有噪声、不完整的时钟周期或不正确的信号级别。
- 时序问题:检查起始位、停止位和ACK信号的时序是否正确。
4. 查看驱动软件的日志和错误码
- 错误信息:分析驱动或操作系统提供的错误信息或状态码,它们可以提供关于何种类型的I2C错误发生的线索。
- 调试信息:如果可能,增加日志输出,在发送和接收函数中添加打印信息,以监控程序流程和变量状态。
5. 单步调试和代码审查
- 单步执行:使用调试器逐步执行代码,检查在何处失败。观察寄存器状态和变量值是否符合预期。
- 代码审查:仔细检查代码逻辑,确保没有编程错误,如错误处理逻辑、循环条件等。
6. 简化代码和隔离问题
- 最小化代码测试:简化代码到最基本的发送和接收操作,逐步增加功能,以确定引入问题的确切位置。
虚拟内存和物理内存区别
定义:
- 物理内存:也称为实际内存或主存,是计算机硬件中实际存在的存储设备,用于存储程序和数据。
- 虚拟内存:是一种计算机内存管理技术,将磁盘空间用作扩展的内存,使得程序能够运行的内存空间超出物理内存的限制。
访问速度:
- 物理内存:由于是直接访问硬件,速度较快。
- 虚拟内存:由于需要通过硬盘进行数据交换,访问速度通常较慢。
容量:
- 物理内存:容量有限,通常受到硬件限制。
- 虚拟内存:容量可以远远大于物理内存,取决于可用的磁盘空间。
作用:
- 物理内存:直接存储程序和数据,供CPU直接访问。
- 虚拟内存:扩展了物理内存的容量,使得系统可以运行比物理内存更大的程序,并且提供了一种机制来管理和保护内存,防止程序之间的相互干扰。
管理方式:
- 物理内存:通常由操作系统和硬件共同管理。
- 虚拟内存:由操作系统负责管理,包括虚拟内存到物理内存的映射、页面置换算法等。
虚拟内存的引入使得程序能够以更大的内存空间运行,同时提供了一种机制来实现内存保护和共享,但也增加了系统的复杂性和运行开销。
应用层随便写个地址,内核是怎么检测出异常的
内存访问权限检查: 内核首先检查应用程序尝试访问的地址是否在其分配的虚拟地址空间范围内,以及是否具有合适的访问权限(读、写、执行)。如果地址无效或访问权限不符合要求,内核会立即触发异常。
页表检查: 内核会根据页表信息检查应用程序访问的虚拟地址是否有对应的物理地址映射。如果没有有效的映射或者映射出错(例如页面不存在、页表错误等),则会引发页错误(Page Fault)异常。
访问违规检查: 内核还会检查应用程序的访问是否符合硬件和操作系统的规则。例如,尝试访问内核空间的地址(内核空间不允许用户态程序直接访问)、尝试访问受保护的系统资源等情况都会触发异常。
边界检查: 在某些情况下,内核可能会对访问的地址进行边界检查,以确保不会越界访问其他内存区域。
处理器异常处理机制: 当发现异常时,处理器会暂停当前指令的执行,并转入内核异常处理程序。内核会根据异常类型和上下文信息,采取适当的措施来处理异常,例如通过发送信号通知应用程序、终止应用程序、重新映射内存等。
总的来说,内核通过一系列的检查和处理机制来检测并处理应用程序访问内存的异常,以确保系统的稳定性和安全性。异常处理过程中,内核会采取适当的措施来保护系统免受潜在的威胁,同时尽可能地维持应用程序的正常执行。
如果设备树随便写个错误字符串,内核驱动怎么处理的
解析错误: 内核在启动过程中会尝试解析设备树,将其转换为内部数据结构以供内核使用。如果设备树中包含错误的字符串或格式不正确,解析过程可能会失败,导致内核无法正确识别和配置硬件设备。
错误报告: 内核可能会在启动时输出错误信息,指示设备树中存在解析错误或无效的信息。这些错误消息通常会显示在启动日志中,帮助开发人员诊断和修复问题。
部分加载或忽略: 内核在解析设备树时可能会选择部分加载或忽略错误的部分。这可能会导致部分硬件设备无法正确配置,或者导致某些功能不可用。
容错处理: 驱动程序可能会包含一些容错机制,尝试在设备树中发现错误时进行容错处理。例如,它可能会尝试使用默认配置或尝试从其他来源获取正确的设备信息。
中断加载过程: 如果设备树中存在严重错误,可能会导致内核加载过程中断,系统无法启动。在这种情况下,需要修复设备树中的错误,并重新启动系统。