iOS 【你的项目内存溢出了吗?】
在 App 的开发中,内存溢出、野指针满天飞是很常见的现象。合理的规避内存溢出风险是我们需要做得。常见的,如数组越界,可造成程序的闪退崩溃。但一般这种类型的内存泄露比较容易定位,也容易解决。最近项目中遇到了一些很奇怪的现象,我拿来分享一下。
在我们的 App 中,会打包行车的轨迹点并上传到后台,并根据轨迹进行里程数统计和计费。但是最近一段时间经常有用户反馈公里数异常为 0,费用也不统计了。更奇怪的是这种现象时有时无,由于很难定位到错误发生的地方,所以比较难解决。于是我查看了服务器数据库中我们上传的数据包,发现出现公里数不计算的情况时数据包都被后台拒收了。拒收的原因我们在错误日志中也拿到了,那就是时间异常。正常来说,我们是以毫秒数统计的当前时间和服务器时间进行上传,后台解析出来正确的时间,但是错误日志中显示我们上传的是 1969 年的某一天的时间,而且时间随机没有规律。于是彻底检查了一下代码。
在过程中,我发现我拿到的时间是没有问题的,但上传上去的时间有问题。错误出在了类型转化上。如下错误代码:
// 客户端时间(毫秒数)
long localTime = (long long)[[[NSDate alloc] init] timeIntervalSince1970] * 1000;
本地时间使用了 longLongValue 进行转化(毫秒长度比较长,使用 long 或者 int 长度不够。long、int 为 4 字节,而 long long 则是 8 字节。),但是却用了 long 的指针进行接收。这样一来就出现了一块没有指针指向的僵尸内存。为什么这么说呢,先看一下下面两篇文章:
我们发现基本数据类型 OC 是继承于 C 的,long 在 16 位、32 位编译器下所占 4 个字节、在 64 位编译器下占 8 个字节。而 long long 在 16 位、32 位、64 位编译器下均占 8 个字节。那么我们用 long 型的指针去接收 long long 类型的数据,在 16 位、32 位的编译环境下就会出问题。我们知道,指针可以指向该内存空间并且持有该内存空间,什么意思呢?一旦一块内存空间被指针所指向,那么就可以通过这个指针去操作这块内存空间使用,如果该指针还持有了该内存空间,那么该内存空间就无法被其他的指针来访问。
回到问题中来,我们用 long 型指针去接收 long long 类型的数据,那么这个数据所在的内存空间只有 4 位被 long 型指针所持有,剩下的 4 位内存空间是没有被持有的,那么当手机内存剩余量不足、进程过多的情况下,系统就会拿到这部分没有被持有的内存分配给其他的进程使用,这样一来我们之前的时间数据所占内存就会缺失。 由于内存如同一个栈,占用内存后这部分会向前挤压, 0 1 编码会溢出,那么这个内存所表示的数据很有可能根据符号位的不同而产生一个负数(二进制符号位 0 代表正数,1 代表负数),而上传到服务器端负数的毫秒数会解析成一个 1969 年的错误日期,这样一来就拒绝了我们上传的数据包。
经大量数据的分析统计,出现情况的手机大都内存剩余量不足,而一些内存剩余量比较充足的手机使用软件就不会出现这个问题。
所以说,在使用数据类型的时候一定要门当户对,而内存的把控也要做到心里有数才行。
上一篇: Vue数据双向绑定的原理以及实现
下一篇: 双向绑定介绍以及vue双向绑定的原理说明