内存重叠问题分析与解决方案

本文记录了一次图像识别模块开发过程中遇到的诡异问题——连续拍摄的两张图片在内存中显示内容相同,但保存为文件后内容却不同。作者通过深入分析内存映射原理找到了原因并给出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
在编写图像识别模块时,遇到了一个莫名的大问题,(如代码所示)
unsigned char *image0, *image1;
image0 
= get_image_from_camera(...);
image1 
= get_image_from_camera(...);
以上代码是连续拍摄两张照片,但奇怪的是,拍摄完毕时发现,image0保存的图片内容和image1的内容竟然完全相同!!!!太不可思议了。首先,通过如下代码排除了获取照片错误的问题:
 
image0 = get_image_from_camera(...);
write_jpeg(image0...);
image1 
= get_image_from_camera(...);
write_jpeg(image1...);
以上代码的含义是拍摄下图片后立即保存为jpeg文件,这样我就能检测两张图片是否内容相同,不出所料,检测结果显示两个jpeg文件的图片内容是完全不同的。但即使是这样,在以上操作后,依旧发现image0和image1指向的图片内容相同。似乎是中邪了,保存的jpeg文件内容不同,但是指针指向的却是相同的内容(都是image1的内容,也就是后一张图片)。然后想着,是不是在获取image1的同时,把image0的内存区域给覆盖了,这个是很有可能的,那么这个问题就100%出在get_image_from_camera函数中。打开这个函数的定义发现:
char *map;
...
map 
=
 malloc(...);
...
return (map);
 
这个就和我想的不一样了,这个函数非常正确,它在获取图像时,是采用了动态内存分配,并且返回内存区域的首地址,这样的话,就根本不可能会出现内存覆盖的现象。至此,这个问题一直困扰了我半个星期,一点进展都没有,大脑一团浆糊,唯一想的就是中邪了。
然后,就在n天后,吃饱了撑的,在校园里走着,忽然脑袋里想起了我们在用户空间中的内存地址都是虚拟内存地址,也就是需要通过内存映射,才能够访问到物理地址的。那么这样的映射关系到底是什么关系呢?第一个闪现的就是一一映射,也就是说只允许唯一的虚拟地址去映射唯一的物理地址。那么到底有没有其它的可能性呢?一对多?这个马上被否定了,因为假如一个虚拟地址能够映射多个物理地址的话,根本是不可能实现的,因为操作系统无法分清某一时刻这个虚拟地址到底要映射到哪个物理地址上。那么多对一呢?也就是说多个虚拟地址可以映射到唯一的物理地址上?也就是说通过不同的虚拟地址,我们可以访问同一个物理地址。这个可行。忽然间就豁然开朗,考虑到项目上出的那个奇怪的问题,会不会是image0和image1同时映射到了相同的物理地址上?
以上分析确实有硬伤,当时没怎么细想,解决方案可行,并且没有大问题,就记了下来,……其实,通过共享内存的方式很容易就能实现,动态分配的内存映射到进程地址空间的同一位置,比较郁闷,没想到这一点,一开始以为是分配的内存在内核空间直接映射到了camera的缓存里……后来,也证实了共享内存的这个想法,就此改正。
但是由于时间关系,没能确实的验证,但是基于这个不晓得是对是错的设想,却很容易的想出了解决问题的办法,代码缩写如下:
image0 = get_image(...);
image0_tmp 
= (unsigned char *)malloc(image_size);
memset(image0_tmp, 
0, image_size);
memcpy(image0_tmp, image0, image_size);
image1 
= get_image(...);
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值