1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > ios 内存深度优化_iOS性能优化之内存(memory)优化

ios 内存深度优化_iOS性能优化之内存(memory)优化

时间:2021-09-12 00:44:02

相关推荐

ios 内存深度优化_iOS性能优化之内存(memory)优化

近期在工作中,对APP进行了内存占用优化,减少了不少内存占用,在此将经验进行总结和分享,也欢迎大家进行交流。

在优化的过程中,主要使用了以下工具:

Instruments和Allocations

这个工具能显示出应用的实际内存占用,并可以按大小进行排序。我们只要找出那些占用高的,分析其原因,找到相应的解决办法。

MLeaksFinder

腾讯开源的一款内存泄漏查找工具,可以在使用APP的过程中,即时的提醒发生了内存泄漏。

Xcode的Memory Graph

这款工具在查找内存泄漏方面,可以作为MLeaksFinder的补充,用于分析对象之间的循环引用关系。

另外通过分析某个时刻的Live Objects,可以分析出哪些是不合理的。

总结下来,主要有几方面的原因导致内存占用高:

使用了不合理的API

网络下载的图片过大

第三方库的缓存机制

Masonry布局框架

没必要常驻内存的对象,实现为常驻内存

数据模型中冗余的字段

内存泄漏

下面从这几方面展开讨论。

1.使用了不合理的API

1.1 对于仅使用一次或是使用频率很低的大图片资源,使用了[UIImage imageNamed:]方法进行加载

图片的加载,有两种方式,一种是[UIImage imageNamed:],加载后系统会进行缓存,且没有API能够进行清理;另一种是[UIImage imageWithContentsOfFile:]或[[UIImage alloc] initWithContentsOfFile:],系统不会进行缓存处理,当图片没有再被引用时,其占用的内存会被彻底释放掉。

基于以上特点,对于仅使用一次或是使用频率很低的大图片资源,应该使用后者。使用后者时,要注意图片不能放到Assets中。

1.2 一些图片本身非常适合用9片图的机制进行拉伸,但没有进行相应的优化

图片的内存占用是很大的,对于适合用9片图机制进行拉伸处理的图片,可以切出一个比实际尺寸小的多的图片,从而大量减少内存占用。比如下面的图片:

contract_right_green@3x.png

左右两条竖线之间的部分是纯色,那么设计在切图时,对于这部分只要切出来很小就可以了。然后我们可以利用Xcode的slicing功能,设定图片哪些部分不进行拉伸,哪些部分进行拉伸。在加载图片的时候,还是以正常的方式进行加载。

1.3在没有必要的情况下,使用了-[UIColor colorWithPatternImage:]这个方法

项目中有代码使用了UILabel,将label的背景色设定为一个图片。为了将图片转为颜色,使用了上述方法。这个方法会引用到一个加载到内存中的图片,然后又会在内存中创建出另一个图像,而图像的内存占用是很大的。

解决办法:此种场景下,合理的是使用UIButton,将图片设定为背景图。虽然使用UIButton会比UILabel多生成两个视图,但相比起图像的内存占用,还是完全值得的。

1.4 在没有必要的情况下,使用Core Graphics API,修改一个UIImage对象的颜色

使用此API,会导致在内存中额外生成一个图像,内存占用很大。合理的做法是:

设定UIView的tintColor属性

将图片以UIImageRenderingModeAlwaysTemplate的方式进行加载

代码示例:

1.5 基于颜色创建纯色的图片时,尺寸过大

有时,我们需要基于颜色创建出UIImage,并用做UIButton在不同状态下的背景图片。由于是纯色的图片,那么,我们完全没有必要创建出和视图大小一样的图像,只需要创建出宽和高均为1px大小的图像就够了。

代码示例:

1.6 创建水平的渐变图像时,尺寸过大

项目中有些地方基于颜色,利用Core Graphics,在内存中创建了水平方向从左到右的渐变图像。图像的大小为视图的大小,这在某些视图较大的场合,造成了不小的内存开销。以在@3x设备上一个400x60大小的视图为例,其内存开销为:

400 * 3 * 60 * 3 * 4 / 1024 = 210KB。

但是实际上这个图像,如果是400px宽,1px高,完全能达到相同的显示效果,而其内存开销则仅为:

400 * 1 * 4 / 1024 = 1.56KB

1.7 在自定义的UIView子类中,利用drawRect:方法进行绘制

自定义drawRect会使APP消耗大量的内存,视图越大,消耗的越多。其消耗内存的计算公式为:

消耗内存 = (width * scale * height * scale * 4 / 1024 / 1024)MB

几乎在所有情况下,绘制需求都可以通过CAShapeLayer这一利器来实现。CAShapeLayer在CPU和内存占用两项指标上都完爆drawRect:。

其有以下优点:

渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。

高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。

不会被图层边界剪裁掉。

不会出现像素化。

1.8 在自定义的CALayer子类中,利用- (void)drawInContext:方法进行绘制

与上一条类似,请尽量使用CAShapeLayer来做绘制。

1.9 UILabel尺寸过大

如果一个UILabel的尺寸,大于其intrinsicContentSize,那么会引起不必要的内存消耗。所以,在视图布局的时候,我们应该尽量使UILabel的尺寸等于其intrinsicContentSize。

关于这一点,读者可以写一个简单的示例程序,然后利用Instruments工具进行分析,可以看到Allocations中,Core Animation这一项的占用会明显增加。

1.10 为UILabel设定背景色

如果设置的背景色不是clearColor, whiteColor,会引起内存开销。

所以,一旦碰到这种场合,可以将视图结构转变为UIView+UILabel,为UIView设定背景色,而UILabel只是用来显示文字。

这一点也可以通过写示例程序,利用Instruments工具来进行验证。

2.网络下载的图片过大

几乎所有的iOS应用,都会使用SDWebImage这一框架进行网络图片的加载。有时会遇到加载的图片过大的情况,对于这种情况,还需要根据具体的场景进行分析,采用不同的解决办法。

2.1 视图很大,图片不能被缩放

如果图片大是合理的,那么我们做的只能是在视图被释放时,将下载的图片从内存缓存中删除。示例代码如下:

上述代码将使得内存占用较高的情况只会出现在某个页面中,一旦从此页面返回,内存将会回归正常值。

2.2 视图小,这时图片应该被缩放

如果用于显示图片的视图很小,而下载的图片很大,那么我们应该对图片进行缩放处理,然后将缩放后的图片保存到SDWebImage的内存缓存中。

示例代码如下:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。