by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • 11:09
    kinarobin closed #3054
  • 05:25
    arslan311 edited #3059
  • 05:22
    arslan311 opened #3059
  • Aug 02 09:34
    mahadshahib opened #3058
  • Aug 01 08:26
    stale[bot] labeled #2928
  • Aug 01 08:26
    stale[bot] labeled #3022
  • Jul 31 10:35
    yyhinbeijing edited #3056
  • Jul 31 03:41
    yyhinbeijing edited #3057
  • Jul 31 03:41
    yyhinbeijing edited #3057
  • Jul 31 03:40
    yyhinbeijing edited #3057
  • Jul 31 03:40
    yyhinbeijing edited #3057
  • Jul 31 03:39
    yyhinbeijing opened #3057
  • Jul 31 03:05
    yyhinbeijing edited #3056
  • Jul 29 09:51
    yyhinbeijing edited #3056
  • Jul 29 09:48
    yyhinbeijing opened #3056
  • Jul 29 09:00
    dreampiggy unlabeled #2963
  • Jul 29 05:09
    stale[bot] labeled #2963
  • Jul 25 16:20
    dreampiggy labeled #3055
  • Jul 25 16:20
    dreampiggy labeled #3055
  • Jul 25 16:20
    dreampiggy closed #3055
DreamPiggy
@dreampiggy
你看我那个Commit吧,因为这里有两个NSPointerArray,但是@synchronized只是一把锁
这两个NSPointerArray进行加锁的时机并不是同时的(一个是Manager的callback,一个是NSOperationQueue的callback),当存在prefetchOperations 1 锁定,loadOperations 2锁定,这时候再进入一个新的prefetchOperations3 锁定,就会进入互相等待的死锁状态
这里解释了原因。。还看不懂的话再阅读以下源码
LivyNN
@LivyNN

我仔细看了很久代码,但是感觉这个死锁不是prefetchOperation和loadOperation之间的锁,因为loadOperation的回调中没有需要锁token的地方,所以Manager和Prefetcher的两个线程中只有prefetcher的线程中有锁的嵌套,Manager的回调中没有锁,@sychronized本身是可以重入的锁,一条线程应该死锁不了。

这个死锁我认为是Token和SDAsyncBlockOperation之间的死锁,因为在SDAsyncBlockOperation的start方法中锁了自己,在自己的executionBlock中又为了加Operation锁住了Token;另一方面是在cancel的时候先锁了Token,然后调用每个SDAsyncBlockOperation的cancel,而cancel的时候它又锁了自己。
这样的话 在主线程上是cancel函数: 锁Token->锁SDAsyncBlockOperation , 在prefetcher线程上是:锁SDAsyncBlockOperation->锁Token,这样导致的死锁,两条锁住的线程是主线程和prefetcher线程,loader的线程没有锁住。

而把Token的锁替换为两把锁之后就变成了,cancel的时候:锁TokenLock1->锁SDAsyncBlockOperation 和 Prefetcher线程上的:锁SDAsyncBlockOperation->锁TokenLock2, 这样就不会锁住。

@dreampiggy
我写Demo怎么都没法用之前你说的的这种场景把自己的程序锁住,sychronized的锁嵌套很多层,它自己最后都解开了。
只有两条线程反方向互相锁才能锁住
DreamPiggy
@dreampiggy
你理解的是对的,synchronized用的是recursive lock,同一个,线程,锁多次可以正常解锁。那个问题是跨越2个线程的,一个是主线程,一个是NSOperationQueue线程
LivyNN
@LivyNN
好的,感谢~
DreamPiggy
@dreampiggy
SDWebImage 5.8.0 released. This version introduce the feature to query and transform the original cache without downloading, aniamted image enhancement, prefetcher bugfix, see full changelog: https://github.com/SDWebImage/SDWebImage/releases/tag/5.8.0
Lee0820
@Lee0820
你好,我这是大概是这样一个场景,有一个图片浏览器显示的功能,图片是类似新闻稿件里的图片,当我遇到某个稿件是大概20张图的话,大概有 10几个GIF,用SDAnimatedImageView后内存也是很高,请教下这种情况要怎么处理 ~
DreamPiggy
@dreampiggy
MR给你回复的策略测试了吗,真机,并且使用optionsProcessor禁止UIImageView加载动图
Lee0820
@Lee0820
是真机,现在没有使用UIImageView加载动图
DreamPiggy
@dreampiggy
那为什么会有高占用?本身默认的maxBufferSize根据free和total内存算出来的,不会超过40%
有Demo URL吗
Lee0820
@Lee0820
NSArray *srcStringArray = @[ @"https://xhossc.app.xinhuanet.com/download-source/img/2bfb6343adcb414fbe9e59eaeb0d5da1.png",
@"https://xhossc.app.xinhuanet.com/download-source/img/92dca08b9cde4ecf8f1a5e03256cde85.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/b46d659199344011a6f425afef3e7787.jpeg",
@"https://xhossc.app.xinhuanet.com/download-source/img/766c79bb7b6a4998b7677d364afdf887.jpeg",
@"https://xhossc.app.xinhuanet.com/download-source/img/2d93a805ff744e0bb4ece1888018f36c.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/ac326e43460c471a989d47977bdc1f1b.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/ec6226198a4845e6a0e312427dbf0f6b.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/5f0f5cc7d61a42d4859ff1676bb842ef.jpeg",
@"https://xhossc.app.xinhuanet.com/download-source/img/1eef90dcc1b0444594dcd512efaad5ae.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/87c900f6784e4487887f27c1f9c68bdc.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/134e4019493e414fbf9289a4b9067a13.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/e5f1f01f1940461ba79478c7d8f03b2f.jpeg",
@"https://xhossc.app.xinhuanet.com/download-source/img/e83c50148e684d8daec1b240c9cc3321.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/2ec6048376194fbe89e5d8a69bb96e84.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/8f680a785bf24293a9be66f98fe9a09d.jpeg",
@"https://xhossc.app.xinhuanet.com/download-source/img/da6471db01e8411087d893814409ec02.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/3005d7f24fcd496b92f0bcd5b085b4c6.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/5399d9ee8cf74b1e81924c671e489ce3.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/f91326247bc94332a7446a348a954e6a.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/5c491084a6c74dd19b584a71945c38ca.gif",
@"https://xhossc.app.xinhuanet.com/download-source/img/bac63ea94e824007afa0b03334f0c319.jpeg"
];
DreamPiggy
@dreampiggy
你这GIF,640 × 896,55帧,用SDAnimatedImageView能承载啊。UIImageView肯定不行,全加载到内存,一张就是120.3125MB
你自己检查一下,利用Xcode那个Live Object(Memory Debug)按钮,看看有没有叫做_UIAnimatedImage的对象存在
正常的应该是SDAnimatedImage对象
Lee0820
@Lee0820
查了几个gif,有的单个gif可能会有几十张,甚至80个
一下子加载会 涨到1.5G左右的内存
DreamPiggy
@dreampiggy
SDAnimatedImageView边解码边渲染,内存总大小是固定的,肯定是你用UIAnimatedImage加载了
或者你难道用了preloadAllFrames?
Lee0820
@Lee0820
我这目前仅仅用了SDAnimatedImageView的这个方法 - (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT;
DreamPiggy
@dreampiggy
我意思其他地方,UIImageView提前帮你渲染了
要“全App缓存中”无任何UIAnimatedImage。你用那个OptionsProcessor代码贴进去再试一次。感觉你好像压根没实验
DreamPiggy
@dreampiggy
自己用iPhone真机测试,把你贴的所有URL放到List中加载,iPhone XR占用内存在750MB,属于符合预期的值(按照那个默认规则计算,free为1.5GB,total为3GB)
截屏2020-05-25下午3.38.52.png
你说的会Crash是什么状况?
Lee0820
@Lee0820
好的,我查一下,之前的crash,就是在7p上,内存达到1.5G后,就被系统杀死了,提示gif Message from debugger: Terminated due to memory
DreamPiggy
@dreampiggy
之前的Crash用的版本,是SD 5.8.0?使用了UIImageView?
Lee0820
@Lee0820
是的,我刚在一个demo里改成SDAnimatedImageView 在测试
DreamPiggy
@dreampiggy
按照我那个MR回复,建议的优化,是禁止UIImageView加载动图,只针对SDAnimatedImageView加载动图;如果有特别大图的case下发场景,你可以自行修改所有地方用到的maxBufferSize,让它可控
Lee0820
@Lee0820
52E0CDDF-6C24-493E-ADEF-5B246928B3FE.png
我现在加了
SDWebImageManager.sharedManager.optionsProcessor = [SDWebImageOptionsProcessor optionsProcessorWithBlock:^SDWebImageOptionsResult _Nullable(NSURL _Nullable url, SDWebImageOptions options, SDWebImageContext * _Nullable context) {
// Check SDAnimatedImageView
if (!context[SDWebImageContextAnimatedImageClass]) {
options |= SDWebImageDecodeFirstFrameOnly;
}
return [[SDWebImageOptionsResult alloc] initWithOptions:options context:context];
}];
内存大概在700--1.8G之间循环跳动
DreamPiggy
@dreampiggy
看起来每次波峰是因为打到OOM阈值了被自动clear掉历史的frames了
不过,有问题啊,你的Example还是project,为什么和我行为不一样?我这里不会一直涨呀,你加载了多少图
感觉你这里的数量应该是给我发的URL的倍数
看起来你这个像是一个SDK App,开源的吗,能共享出来直接Debug下不
Lee0820
@Lee0820
可以的,我发你邮箱 ~
Lee0820
@Lee0820
已经发了
Lee0820
@Lee0820
你好,maxBufferSize参数的作用我没太看懂,0表示通过计算当前内存使用量自动调整。
1意味着没有任何缓冲缓存,每个帧将被解码,然后16m在渲染后释放。(最低内存和最高CPU),设置成1,大概只有160M左右 ~,能简单解释下吗,感谢
DreamPiggy
@dreampiggy
拿CPU换时间呀
每帧都要解码,CPU占用率高
解码渲染后立即销毁,内存释放。不过动图频率高了或者解码慢,就会lag
Lee0820
@Lee0820
昨天那个demo,一直涨的问题您这边有debug吗 ~
DreamPiggy
@dreampiggy
我今天或明天抽空看一下,有Full Time Job有时会忙
Lee0820
@Lee0820
好的,辛苦了,感谢