我制作了一个拍摄原始图像并将其调整为3种不同缩放比例的功能 - > 16x,10x和4x。为了更好地理解,请继续阅读本段。假设原始图像是1000x1000。我声明在1倍变焦时它的尺寸将是50x50。这意味着4倍变焦将是200x200,10倍变焦将是500x500,16倍变焦将是800x800。因此我的功能需要将原始的1000x1000调整为800x800,然后降低到500x500,然后降低到200x200。请注意我已成功完成此操作并我的问题是关于内存使用情况。
下面我有两种方法。这两种方法都有效,但有一种方法会造成巨大的内存使用膨胀,使用大约3倍/ 4倍的内存...我更喜欢第二种方法,因为它的加载速度明显快于第一种方法,因为它没有调整3个图像中的每一个从原始图像,而不是从先前调整大小的图像调整它们。
注意:我正在使用Xcode Instruments来测量内存使用情况。 ImageResizer类包含一个名为“Resize”的函数,它可以调整Image的大小。
方法1。)
public List<UIImage> InitImageList_BFObjects ( UIImage image, SizeF frameSize )
{
List<UIImage> listOfImages = new List<UIImage>();
for ( int i = 0; i < 3; i++ )
{
if ( i == 0 )
zoomScale = 16f;
else if ( i == 1 )
zoomScale = 10f;
else// if ( i == 2 )
zoomScale = 4f;
Resizer = new ImageResizer(image);
Resizer.Resize(frameSize.Width * zoomScale, frameSize.Height * zoomScale);
UIImage resizedImage = Resizer.ModifiedImage;
listOfImages.Insert(0, resizedImage);
}
return listOfImages;
}
方法1工作并使用非常少的内存使用量。我用一组约20张图像运行了这个。我的应用程序在加载后使用大约14mb的内存使用量(使用Xcodes Instruments检查内存使用情况)
方法2。)
public List<UIImage> InitImageList_BFObjects ( UIImage image, SizeF frameSize )
{
List<UIImage> listOfImages = new List<UIImage>();
for ( int i = 0; i < 3; i++ )
{
if ( i == 0 )
zoomScale = 16f;
else if ( i == 1 )
zoomScale = 10f;
else// if ( i == 2 )
zoomScale = 4f;
if ( listOfImages.Count == 0 )
{
Resizer = new ImageResizer(image);
Resizer.Resize(frameSize.Width * zoomScale, frameSize.Height * zoomScale);
UIImage resizedImage = Resizer.ModifiedImage;
listOfImages.Insert(0, resizedImage);
}
else
{
// THIS LINE CONTAINS THE MAIN DIFFERENCE BETWEEN METHOD 1 AND METHOD 2
// Notice how it resizes from the most recent image from listOfImages rather than the original image
Resizer = new ImageResizer(listOfImages[0]);
Resizer.Resize(frameSize.Width * zoomScale, frameSize.Height * zoomScale);
UIImage resizedImage = Resizer.ModifiedImage;
listOfImages.Insert(0, resizedImage);
}
}
return listOfImages;
}
方法2有效,但内存使用天空火箭!我用大约20张图像组成了同一组。加载后我的应用程序有超过60mb的内存使用量(使用Xcodes Instruments检查内存使用情况)为什么内存使用率如此之高?什么是方法2导致记忆天空火箭?这几乎就好像变量没有得到正确的清理
*其他信息,ImageResizer类 * *
我从我的ImageResizer类中删除了不需要的函数,并将其重命名为“ImageResizer_Abridged”。我甚至切换到使用这个课程,以确保我没有意外地删除任何所需的东西。
public class ImageResizer_Abridged
{
UIImage originalImage = null;
UIImage modifiedImage = null;
public ImageResizer_Abridged ( UIImage image )
{
this.originalImage = image;
this.modifiedImage = image;
}
/// <summary>
/// strech resize
/// </summary>
public void Resize( float width, float height )
{
UIGraphics.BeginImageContext( new SizeF( width, height ) );
//
modifiedImage.Draw( new RectangleF( 0,0, width, height ) );
modifiedImage = UIGraphics.GetImageFromCurrentImageContext();
//
UIGraphics.EndImageContext();
}
public UIImage OriginalImage
{
get
{
return this.originalImage;
}
}
public UIImage ModifiedImage
{
get
{
return this.modifiedImage;
}
}
}
我创建了一个显示此问题的简化测试项目 *
以下是项目的保管箱链接:https://www.dropbox.com/s/4w7d87nn0aafph9/TestMemory.zip
以下是方法1的Xcode Instruments屏幕截图作为证据(内存使用量为9 MB): http://i88.photobucket.com/albums/k194/lampshade9909/AllImagesResizedFromOriginalImage_zps585228c6.jpg
以下是方法2的Xcode Instruments屏幕热门作为证据(55 MB内存使用率): http://i88.photobucket.com/albums/k194/lampshade9909/SignificantIncreaseInMemoryUsage_zps19034bad.jpg
以下是运行测试项目所需的代码块
// Initialize My List of Images
ListOfImages = new List<UIImage>();
for ( int i = 0; i < 30; i++ )
{
// Create a UIImage Containing my original Image
UIImage originalImage = UIImage.FromFile ("b2Bomber.png");
float newWidth = 100f;
float newHeight = 40f;
float zoomScale;
float resizedWidth, resizedHeight;
UIImage resizedImage1;
UIImage resizedImage2;
// Basically, I want to take the originalImage Image and resize it twice.
// Method 1.) Resize the originalImage and save it as ResizedImage1. Resize the originalImage and save it as ResizedImage2. We're finished!
// Method 2.) Resize the originalImage and save it as ResizedImage1. Resize ResizedImage1 and save it as ResizedImage2. We're finished!
// The pro to Method 1 is that we get the best possible quaility on all resized images. The con is, this takes a long time if we're doing dozens of very large images
// The pro to Method 2 is that it's faster than Method 1. This is why I want to use Method 2, it's speed. But it has a HUGE con, it's memory usage.
// Please run this project on an iPad connected to XCodes Instruments to monitor memory usage and see what I mean
zoomScale = 10f;
resizedWidth = newWidth*zoomScale;
resizedHeight = newHeight*zoomScale;
UIGraphics.BeginImageContext( new SizeF( resizedWidth, resizedHeight ) );
originalImage.Draw( new RectangleF( 0, 0, resizedWidth, resizedHeight ) );
resizedImage1 = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
zoomScale = 4f;
resizedWidth = newWidth*zoomScale;
resizedHeight = newHeight*zoomScale;
UIGraphics.BeginImageContext( new SizeF( resizedWidth, resizedHeight ) );
// Run this project on an iPad and examine the memory usage in XCode's Instruments.
// The Real Memory Usage will be aroud 9 MB.
// Uncomment this "originalImage.Draw" line to see this happening, make sure to comment out the "resizedImage1.Draw" line
// originalImage.Draw( new RectangleF( 0, 0, resizedWidth, resizedHeight ) );
// Run this project on an iPad and examine the memory usage in XCode's Instruments.
// The Real Memory Usage will be aroud 55 MB!!
// My question is, why does the memory sky rocket when doing this, and how can I prevent the memory from sky rocketing??
// My App requires me to resize around a hundred images and I want to be able to resize an already resized image (like in this example) without the memory usage sky rocketing like this...
// Uncomment this "resizedImage1.Draw" line to see this happening, make sure to comment out the "originalImage.Draw" line
resizedImage1.Draw( new RectangleF( 0, 0, resizedWidth, resizedHeight ) );
resizedImage2 = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
// Add my resized images to the list of Images
ListOfImages.Add (resizedImage1);
ListOfImages.Add (resizedImage2);
}
答案 0 :(得分:3)
我不确定您的Resize
代码,但我看到Scale
做了奇怪的事情。一旦你深入研究它,这并不奇怪,但它确实不明显。
只要不创建后备UIImage
,创建CGImage
即可非常便宜,内存明智。 IOW iOS 可能不立即分配与新大小匹配的新CGImage
支持图像。该分配将不同,直到需要CGImage
。
在这种情况下,某些代码(如方法1)可能在扩展时几乎不需要额外的内存。但是,您的第二种方法是使用放大的图像(并且需要分配后备CGImage
来执行此操作),因此最终需要内存早期。
如何检查?
将您的resizedImage.Size
与resizedImage.CGImage.Size
进行比较。如果它们不匹配,那么你可能会遇到缓存。
备注强>
我说可能因为缓存逻辑是 unknown (未记录)。我知道这可能与在模拟器和设备上运行有所不同 - 而且在iOS版本之间也有所不同;
缓存是一件好事 - 但它可能会令人惊讶:-)我只希望记录下来。
答案 1 :(得分:0)
您是否检查过Resizer是否实现了Dispose()方法?我没有看到你把它丢弃在任何地方。
我相信您的新代码行正在对整个图像实施缩放,因此增加了内存使用量。
Resizer正在以新的放大比例缩放整个图像,以便将传入的4MB图像缩放到8MB,16MB和32MB,从而消耗内存。
答案 2 :(得分:0)
UIImage
实现IDisposable
,因此最终会有Dispose
的内容。 Resize
方法似乎“丢失”了对modifiedImage
的引用,因此我将Dispose()
它。希望调用者对InitImageList_BFObjects
返回的列表中的所有图像执行相同的操作。或者 类实现IDisposable
并且它已经提升了谁必须处理它的线。但请放心,这些正在创建的图像需要在某个时间某处Dispose()
。
public class ImageResizer_Abridged
{
private readonly UIImage originalImage;
private UIImage modifiedImage;
public ImageResizer_Abridged(UIImage image)
{
this.originalImage = image;
this.modifiedImage = image;
}
/// <summary>
/// stretch resize
/// </summary>
public void Resize(float width, float height)
{
UIGraphics.BeginImageContext(new SizeF(width, height));
//
var oldImage = this.modifiedImage;
this.modifiedImage.Draw(new RectangleF(0, 0, width, height));
this.modifiedImage = UIGraphics.GetImageFromCurrentImageContext();
oldImage.Dispose();
//
UIGraphics.EndImageContext();
}
public UIImage OriginalImage
{
get
{
return this.originalImage;
}
}
public UIImage ModifiedImage
{
get
{
return this.modifiedImage;
}
}
}