unsigned char alloc 和免费问题
Posted
技术标签:
【中文标题】unsigned char alloc 和免费问题【英文标题】:unsigned char alloc and free issue 【发布时间】:2012-06-04 10:57:26 【问题描述】:我对一件奇怪的事情感到困惑......我有一个 unsigned char 数组......我使用 calloc 分配它并在其中记录一些字节数据......但是当我释放这个 unsigned char 并分配它时再次,我看到它在内存中保留了上次分配的相同地址。我明白为什么....但我不明白为什么我第二次尝试在那里写入的数据没有被写入......第一次写入的数据被写入......有人可以解释一下吗? ??????
unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
这就是我分配它的方式...... 实际上我的问题是,由于这种分配,每 2 秒发生一次,我有内存泄漏......但是当我尝试释放分配的内存扇区时,会发生上述情况......:(
如果有人可以帮助我......我会很高兴...... 这是代码...
- (unsigned char*) createBitmapContext:(UIImage*)anImage
CGImageRef imageRef = [anImage CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
bytesPerPixel = 4;
bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
imageRef=nil;
return rawData;
在这段代码中没有我释放(rawData)的部分,因为我无法在这个方法中释放它,我试图在全局范围内定义 rawData 并在调用这个方法后释放它......但没有什么有趣的......
如果有人可以帮助我......我会很高兴......
【问题讨论】:
您需要提供一个完整的代码片段,显示分配和缓冲区写入,以及您如何验证内容。以上内容不足以回答您的问题。 @gavinb done...有什么有趣的想法吗? 【参考方案1】:好的,所以这个方法将UIImage
渲染到一个新分配的字节缓冲区中,并将缓冲区返回给调用者。由于您使用calloc
分配它,它将被初始化为0,然后被图像内容覆盖。
当我释放这个 unsigned char 并再次分配它时,我看到它在内存中保留了上次分配的相同地址
是的,不能保证缓冲区在内存中的位置。假设您在返回的内存上调用 free()
,请求完全相同的大小很可能会返回相同的缓冲区。但是 - 你如何验证内容不是第二次写入?缓冲区中有什么?
我的问题是,由于这种分配,每 2 秒发生一次,我有内存泄漏......但是当我尝试释放分配的内存扇区时,会发生上述情况......:(
如果有泄漏,很可能是在调用该方法的代码中,因为这里没有明显的泄漏。语义显然是调用者负责释放缓冲区。那是怎么做到的呢?
另外,您是否正在验证 CGBitmapContext
是否被正确创建?某些创建标志或参数可能会导致错误。所以添加一个检查context
是否有效(至少不是零)。这可以解释为什么内容没有被覆盖。
确保您的内存得到最新更新的一种简单方法是将您自己的数据写入其中。您可以用计数器填充缓冲区,并在方法之外验证这一点。例如,就在您返回rawData
之前:
static unsigned updateCounter = 0;
memset(rawData, updateCounter & 0xff, width*height*4);
这将循环写入 0-255 到缓冲区中,您可以轻松验证。
另一件事 - 你想用这段代码实现什么?可能有一种更简单的方法可以实现您想要实现的目标。返回没有元数据的裸缓冲区不一定是管理图像的最佳方式。
【讨论】:
我的项目的目的是编写屏幕共享工具。使用这种方法,我想获取像素颜色并与之前的图片进行比较以获得相似性。然后在其他方法中,我得到这两张照片的差异并发送更改的部分。所有这些部分都已完成,但我有这个泄漏。我确定在上下文中,因为我每次都会得到下一张照片。而且我还尝试将内存设置为零 memset(rawData,0,weight*height*4);我释放它后,但还是一样。我明白为什么它每次都返回相同的地址,但我不明白为什么 CGBitmapContextCreate 方法不会覆盖里面的数据。 而且我确定泄漏是在 rawData 的分配中......已经检查了一百种方式...... 是的,我知道参数顺序...但这对我没有帮助 您是否验证了上下文是否正确创建,即。上下文不是零?如答案中所述,如果标志并非全部有效,则您可能无法获得有效的上下文。那么绘制就不会成功,不会覆盖数据。 好的,那么需要更多细节。您如何验证CGBitmapContext
始终有效?您如何验证泄漏是在rawData
的分配中?您可以发布调用createBitmapContext:
的代码吗?如果有泄漏,它必须在调用者的逻辑中,因为内存的所有权被传递出去。【参考方案2】:
所以伙计们,我解决了这个问题...首先我将 createBitmapContext 方法更改为此
- (void) createBitmapContext:(UIImage*)anImage andRawData:(unsigned char *)theRawData
CGImageRef imageRef = [anImage CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
bytesPerPixel = 4;
bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(theRawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
imageRef=nil;
// return theRawData;
然后...除此之外,我错过了将 newRawData 分配给 oldRawData 的部分,因此我有两个指向同一内存地址的指针...所以问题就出在这里...我将此分配部分更改为这个 memcpy(rawDataForOldImage, rawDataForNewImage,newCapturedImage.size.width*newCapturedImage.size.height*4);到这里问题就解决了......谢谢大家
【讨论】:
以上是关于unsigned char alloc 和免费问题的主要内容,如果未能解决你的问题,请参考以下文章
在 C11 中,字符串文字为 char[]、unsigned char[]、char* 和 unsigned char*
std::string 与 unsigned char[] 和 unsigned char* 有啥不同?