iOS10的nano_free nano_relocated crash总结

在将SDWebImage从旧版本升级到4.0时,遇到在iOS10中批量下载图片时出现的crash。crash主要出现在iOS10.0至10.1.1,报错涉及`nano_free`和`nano_relocated`。参考微信团队的文章后,尝试了三种解决方案:1) 修改测试代码,但依然crash;2) 动态分配内存避免nano分区冲突,但导致性能下降;3) 替换nano分区释放函数,降低crash率但未完全解决。最后采用减少内存操作的方法缓解问题。欢迎提供更好的解决方案。
摘要由CSDN通过智能技术生成

             在SDWebImage版本替换时遇见了让人捉狂的crash,旧版本为2011年左右的版本,新版本为4.0版本。替换之后,批量下载图片出现了非常大概率的crash,并且该crash在iOS8,iOS9中没有复现,iOS10.0~iOS10.1.1中大概率复现,iOS10.2中概率下降,但是也是非常容易复现出该问题。

             iOS10.1.1中,crash时报错:“freeing unallocated pointer”。iOS10.2中crash报错为:“reallocated pointer was not allocated”。开始的时候不明确是否是SDWebImage库的问题,堆栈中有nanon_free字样。后查询资料,看到微信团队关于该crash的分析文章与解决方案,终于算找到方向了(链接:https://mp.weixin.qq.com/s/hnwj24xqrtOhcjEt_TaQ9w)。下面就沿着该方案解决问题的过程,总结一下吧,虽然最终也没有算解决掉这个问题。

       按照该方案(方案1)敲出代码进行测试(代码附在后面),用定时器去跑该文章的测试代码,发现仍然crash。

       分析该文章,认为helper分区分配的内存空间,地址处于了nano分区的地址区段,释放时由nano分区释放,导致nano_free方法中,检查认为该内存空间没有在nano分区中分配过,因此报错“指针过度释放”。因此,尝试方案2,方案二替换helper分区的内存分配代码,当内存分配的地址处于nano分区的区段时,则释放该内存,重新申请内存,直到地址区段正确。测试该方案发现,当helper分区分配的内存空间地址不正确后,重新申请的地址空间也大概率不正确,导致分配空间性能严重下降。不可行~

     鉴于第二个方案不可行,因此尝试第三个方案。方案3为,替换nano分区的内存释放函数,替换后,当nano分区释放内存时,检查该指针是否属于helper分区分配,如果是,则把该内存的释放转至helper zone。测试该方案,该方案在iOS10.1.1中跑图片下载功能,crash率下降,下降至和iOS10.2的情况比较类似。根据该方案的crash提示报错分析,应该是iOS10中,不止存在helper分区分配了nano分区地址段的内存,也存在nano分区分配了非nano分区地址区段的内存的情况(感觉iOS10.2就是部分解决了该问题,只是没考虑后一种情况),因此按照这个思路,helper zone释放空间时也进行检测,可能能完全解决这个问题。但是由于每次释放空间之前都检查内存是否由另一个分区分配,会导致性能下降,另外也有项目进度原因,我便没有进行进一步尝试。而是选择了减少内存操作的方法来解决了该功能引起的crash。 附上测试的代码,以供参考。

        代码中若有不对之处,请指正,多谢。

        哪位看到有更好的解决办法的,麻烦告知一下,多谢。


//方案1:微信团队方案,使用guard zone
//效果,只要地址错误一次之后就经常申请错误,导致会反复的申请释放空间

malloc_zone_t *NanoCrashGuardInitialize3();
static malloc_zone_t *s_default_zone = NULL;
static malloc_zone_t *s_guard_zone = NanoCrashGuardInitialize3();
typedef void *(*GuardMalloc)(struct _malloc_zone_t *zone, size_t size);
typedef void (*GuardFree)(struct _malloc_zone_t *zone, void *ptr);
typedef size_t (*GuardSize)(struct _malloc_zone_t *zone, const void *ptr);
typedef void * (*GuardCalloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size);
typedef void * (*GuardValloc)(struct _malloc_zone_t *zone, size_t size);
typedef void *(*GuardRealloc)(struct _malloc_zone_t *zone, void *ptr, size_t size);
typedef void (*GuardBatchFree)(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed);
typedef void *(*GuardMemalign)(struct _malloc_zone_t *zone, size_t alignment, size_t size);
typedef void (*GuardFreeDefiniteSize)(struct _malloc_zone_t *zone, void *ptr, size_t size);
typedef size_t (*GuardPressureRelief)(struct _malloc_zone_t *zone, size_t goal);
typedef unsigned (*GuardBatchMalloc)(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested);

GuardMalloc s_default_zone_origin_malloc = NULL;
GuardFree s_default_zone_origin_free = NULL;
GuardSize s_default_zone_origin_size = NULL;
GuardCalloc s_default_zone_origin_calloc = NULL;
GuardValloc s_default_zone_origin_valloc = NULL;
GuardRealloc s_default_zone_origin_realloc = NULL;
GuardBatchMalloc s_default_zone_origin_batch_malloc = NULL;
GuardBatchFree s_default_zone_origin_batch_free = NULL;
GuardMemalign s_default_zone_origin_memalign = NULL;
GuardFreeDefiniteSize s_default_zone_origin_free_definite_size = NULL;
GuardPressureRelief s_default_zone_origin_pressure_relief = NULL;

void *default_zone_malloc(struct _malloc_zone_t *zone, size_t size){
    return s_guard_zone->malloc(s_guard_zone, size);
}

void default_zone_free(struct _malloc_zone_t *zone, void *ptr){
    size_t s = s_guard_zone->size(s_guard_zone, ptr);
    if (s) {
        return s_guard_zone->free(s_guard_zone, ptr);
    }
    return s_default_zone_origin_free(zone, ptr);
}

size_t default_zone_size(struct _malloc_zone_t *zone, const void *ptr){
    size_t s = s_guard_zone->size(s_guard_zone, ptr);
    if (s) {
        return s;
    }
    return s_default_zone_origin_size(zone, 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值