[iOS] UnloadUnusedAssets crash when using UnityWebRequest instead of WWW

We replaced our use of WWW with UnityWebRequest and we started getting an intermittent crash when calling UnloadUnusedAssets. It seems the iPhone6+ suffers the worst (probably due to the large resolution vs the relatively smaller memory size).

* thread #1: tid = 0x1137fc, 0x000001020d9c0000, queue = 'com.apple.main-thread', activity = 'starting resolver activity', stop reason = EXC_BAD_ACCESS (code=1, address=0x1020d9c0000)
    frame #0: 0x000001020d9c0000
  * frame #1: 0x00000001013c9a04 waffle`::ConnectScriptingWrapperToObject() + 80 at Scripting.cpp:153 [opt]
    frame #2: 0x000000010130fa9c waffle`::scripting_unity_engine_object_new() + 40 at ScriptingBackendApi_Il2Cpp.cpp:265 [opt]
    frame #3: 0x0000000100c719c0 waffle`::smile:ownloadHandlerTexture_InternalGetTexture_m2724505187(__this=0x0000000121990d80, method=0x0000000000000000) + 80 at Bulk_UnityEngine_1.cpp:27448
    frame #4: 0x0000000100c7195c waffle`::smile:ownloadHandlerTexture_get_texture_m18006899(__this=0x0000000121990d80, method=0x0000000000000000) + 36 at Bulk_UnityEngine_1.cpp:27437
    frame #5: 0x000000010051baa8 waffle`::U3CGetImageU3Ec__Iterator1_MoveNext_m4206107889(__this=0x000000011e5c19c0, method=0x000000013e83a5b0) + 3640 at Bulk_Assembly-CSharp_7.cpp:9451
    frame #6: 0x000000010010482c waffle`InterfaceFuncInvoker0<bool>::Invoke(slot=1, declaringInterface=0x000000013da31320, obj=0x000000011e5c19c0) + 72 at GeneratedInterfaceInvokers.h:35
    frame #7: 0x0000000100c97bc0 waffle`::SetupCoroutine_InvokeMoveNext_m3556339879(__this=0x0000000000000000, ___enumerator0=0x000000011e5c19c0, ___returnValueAddress1=(___m_value_0 = 0x000000016fd4949f), method=0x000000013db2c4b0) + 336 at Bulk_UnityEngine_2.cpp:15410
    frame #8: 0x00000001011893e0 waffle`RuntimeInvoker_Void_t2863195528_Il2CppObject_IntPtr_t(method=0x000000013db2c4b0, obj=0x0000000000000000, args=0x000000016fd49418) + 92 at Il2CppInvokerTable.cpp:2232
    frame #9: 0x0000000101b09e78 waffle`il2cpp::vm::Runtime::Invoke(MethodInfo const*, void*, void**, Il2CppException**) + 68
    frame #10: 0x00000001013c4c24 waffle`::Invoke() + 80 at ScriptingInvocation.cpp:175 [opt]
    frame #11: 0x00000001013b71dc waffle`::InvokeMoveNext() [inlined] Invoke + 12 at ScriptingInvocation.h:51 [opt]
    frame #12: 0x00000001013b71d0 waffle`::InvokeMoveNext() + 112 at Coroutine.cpp:211 [opt]
    frame #13: 0x00000001013b6f24 waffle`::Run() + 48 at Coroutine.cpp:235 [opt]
    frame #14: 0x0000000101364084 waffle`::InvokeCoroutine() + 48 at AsyncOperation.cpp:18 [opt]
    frame #15: 0x00000001015cc5c0 waffle`::Job_InvokeCoroutine() + 20 at WebRequestProto.h:84 [opt]
    frame #16: 0x00000001012ab908 waffle`::Exec() [inlined] ExecuteJobFunc + 16 at JobQueue.cpp:361 [opt]
    frame #17: 0x00000001012ab8f8 waffle`::Exec() + 100 at JobQueue.cpp:388 [opt]
    frame #18: 0x00000001012abd14 waffle`::ExecuteJobFromMainQueue() + 100 at JobQueue.cpp:777 [opt]
    frame #19: 0x00000001012ab518 waffle`::ExecuteOneJobOnMainThread() + 12 at JobQueue.cpp:1445 [opt]
    frame #20: 0x0000000101373c48 waffle`::PlayerLoop() [inlined] PostLateUpdate_ExecuteOneJobInMainThread + 2032 at Player.cpp:1681 [opt]
    frame #21: 0x0000000101373c44 waffle`::PlayerLoop() + 2028 at Player.cpp:2159 [opt]
    frame #22: 0x0000000101605478 waffle`::UnityPlayerLoopImpl() + 20 at LibEntryPoint.mm:245 [opt]
    frame #23: 0x00000001000c6500 waffle`::UnityRepaint() + 64 at UnityAppController+Rendering.mm:231
    frame #24: 0x00000001000c64b4 waffle`::-[UnityAppController(self=0x000000013c7a7a90, _cmd="repaint") repaint]() + 96 at UnityAppController+Rendering.mm:60
    frame #25: 0x00000001000c6414 waffle`::-[UnityAppController(self=0x000000013c7a7a90, _cmd="repaintDisplayLink") repaintDisplayLink]() + 112 at UnityAppController+Rendering.mm:47
    frame #26: 0x000000010522caa0 libMTLInterpose.dylib`-[DYDisplayLinkInterposer forwardDisplayLinkCallback:] + 184
    frame #27: 0x000000018406022c QuartzCore`CA::smile:isplay::smile:isplayLinkItem::dispatch() + 40
    frame #28: 0x00000001840600e0 QuartzCore`CA::smile:isplay::smile:isplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 424
    frame #29: 0x000000018179de54 IOKit`IODispatchCalloutFromCFMessage + 372
    frame #30: 0x00000001814c5030 CoreFoundation`__CFMachPortPerform + 180
    frame #31: 0x00000001814dd7d4 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56
    frame #32: 0x00000001814dcf0c CoreFoundation`__CFRunLoopDoSource1 + 436
    frame #33: 0x00000001814dac64 CoreFoundation`__CFRunLoopRun + 1800
    frame #34: 0x0000000181404c50 CoreFoundation`CFRunLoopRunSpecific + 384
    frame #35: 0x0000000182cec088 GraphicsServices`GSEventRunModal + 180
    frame #36: 0x00000001866f2088 UIKit`UIApplicationMain + 204
    frame #37: 0x00000001000ba540 waffle`main(argc=1, argv=0x000000016fd4ba78) + 208 at main.mm:32
    frame #38: 0x0000000180fa28b8 libdyld.dylib`start + 4

AND…

* thread #1: tid = 0x112ec5, 0x000000000102078c, queue = 'com.apple.main-thread', activity = 'starting resolver activity', 7 messages, stop reason = EXC_BAD_ACCESS (code=1, address=0x102078c)
    frame #0: 0x000000000102078c
  * frame #1: 0x0000000100c5c22c waffle`::Texture_Internal_GetWidth_m1143336192(__this=0x0000000000000000, ___t0=0x000000011f46b520, method=0x0000000000000000) + 84 at Bulk_UnityEngine_3.cpp:13065
    frame #2: 0x0000000100c5c2c0 waffle`::Texture_get_width_m1557399609(__this=0x000000011f46b520, method=0x00000001465756f0) + 40 at Bulk_UnityEngine_3.cpp:13080
    frame #3: 0x00000001000b0fd0 waffle`VirtFuncInvoker0<int>::Invoke(slot=4, obj=0x000000011f46b520) + 64 at GeneratedVirtualInvokers.h:35
    frame #4: 0x0000000100b75ae0 waffle`::RawImage_OnPopulateMesh_m1483685179(__this=0x000000011e19e410, ___vh0=0x000000010817af50, method=0x00000001463838d0) + 716 at Bulk_UnityEngine.UI_1.cpp:3031
    frame #5: 0x0000000100b1c3a4 waffle`VirtActionInvoker1<VertexHelper_t3377436606*>::Invoke(slot=41, obj=0x000000011e19e410, p1=0x000000010817af50) + 64 at GeneratedVirtualInvokers.h:47
    frame #6: 0x0000000100b3753c waffle`::Graphic_DoMeshGeneration_m2507046369(__this=0x000000011e19e410, method=0x0000000000000000) + 676 at Bulk_UnityEngine.UI_0.cpp:21357
    frame #7: 0x0000000100b36c14 waffle`::Graphic_UpdateGeometry_m2127951660(__this=0x000000011e19e410, method=0x0000000145113e50) + 88 at Bulk_UnityEngine.UI_0.cpp:21289
    frame #8: 0x00000001000a7610 waffle`VirtActionInvoker0::Invoke(slot=38, obj=0x000000011e19e410) + 64 at GeneratedVirtualInvokers.h:23
    frame #9: 0x0000000100b369c0 waffle`::Graphic_Rebuild_m444579746(__this=0x000000011e19e410, ___update0=3, method=0x0000000145113d10) + 184 at Bulk_UnityEngine.UI_0.cpp:21201
    frame #10: 0x00000001000be364 waffle`InterfaceActionInvoker1<int>::Invoke(slot=0, declaringInterface=0x0000000146374250, obj=0x000000011e19e410, p1=3) + 72 at GeneratedInterfaceInvokers.h:47
    frame #11: 0x0000000100b1f80c waffle`::CanvasUpdateRegistry_PerformUpdate_m4284602133(__this=0x000000010abf1930, method=0x000000014500db90) + 2056 at Bulk_UnityEngine.UI_0.cpp:12691
    frame #12: 0x0000000100bbf874 waffle`::WillRenderCanvases_Invoke_m4113031528(__this=0x0000000108169700, method=0x0000000000000000) + 360 at Bulk_UnityEngine_0.cpp:18077
    frame #13: 0x0000000100bbf700 waffle`::Canvas_SendWillRenderCanvases_m1768133093(__this=0x0000000000000000, method=0x0000000145100290) + 164 at Bulk_UnityEngine_0.cpp:18037
    frame #14: 0x00000001011264ac waffle`RuntimeInvoker_Void_t2863195528(method=0x0000000145100290, obj=0x0000000000000000, args=0x000000016fda5558) + 60 at Il2CppInvokerTable.cpp:643
    frame #15: 0x0000000101aade78 waffle`il2cpp::vm::Runtime::Invoke(MethodInfo const*, void*, void**, Il2CppException**) + 68
    frame #16: 0x0000000101368c24 waffle`::Invoke() + 80 at ScriptingInvocation.cpp:175 [opt]
    frame #17: 0x0000000101557748 waffle`::WillRenderCanvases() [inlined] Invoke + 68 at ScriptingInvocation.h:50 [opt]
    frame #18: 0x0000000101557734 waffle`::WillRenderCanvases() + 48 at CanvasManager.cpp:364 [opt]
    frame #19: 0x0000000101317ad0 waffle`::PlayerLoop() [inlined] PlayerUpdateCanvases + 1656 at Player.cpp:1100 [opt]
    frame #20: 0x0000000101317ab8 waffle`::PlayerLoop() [inlined] PostLateUpdate_PlayerUpdateCanvases at Player.cpp:1601 [opt]
    frame #21: 0x0000000101317ab8 waffle`::PlayerLoop() + 1632 at Player.cpp:2119 [opt]
    frame #22: 0x00000001015a9478 waffle`::UnityPlayerLoopImpl() + 20 at LibEntryPoint.mm:245 [opt]
    frame #23: 0x000000010006a500 waffle`::UnityRepaint() + 64 at UnityAppController+Rendering.mm:231
    frame #24: 0x000000010006a4b4 waffle`::-[UnityAppController(self=0x0000000144f7bc10, _cmd="repaint") repaint]() + 96 at UnityAppController+Rendering.mm:60
    frame #25: 0x000000010006a414 waffle`::-[UnityAppController(self=0x0000000144f7bc10, _cmd="repaintDisplayLink") repaintDisplayLink]() + 112 at UnityAppController+Rendering.mm:47
    frame #26: 0x00000001051e8aa0 libMTLInterpose.dylib`-[DYDisplayLinkInterposer forwardDisplayLinkCallback:] + 184
    frame #27: 0x000000018406022c QuartzCore`CA::smile:isplay::smile:isplayLinkItem::dispatch() + 40
    frame #28: 0x00000001840600e0 QuartzCore`CA::smile:isplay::smile:isplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 424
    frame #29: 0x000000018179de54 IOKit`IODispatchCalloutFromCFMessage + 372
    frame #30: 0x00000001814c5030 CoreFoundation`__CFMachPortPerform + 180
    frame #31: 0x00000001814dd7d4 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56
    frame #32: 0x00000001814dcf0c CoreFoundation`__CFRunLoopDoSource1 + 436
    frame #33: 0x00000001814dac64 CoreFoundation`__CFRunLoopRun + 1800
    frame #34: 0x0000000181404c50 CoreFoundation`CFRunLoopRunSpecific + 384
    frame #35: 0x0000000182cec088 GraphicsServices`GSEventRunModal + 180
    frame #36: 0x00000001866f2088 UIKit`UIApplicationMain + 204
    frame #37: 0x000000010005e540 waffle`main(argc=1, argv=0x000000016fda7a78) + 208 at main.mm:32
    frame #38: 0x0000000180fa28b8 libdyld.dylib`start + 4

We call UnloadUnusedAssets when we receive a memory warning from iOS so it can happen at anytime, UnityWebRequest could be in any state at the time of the call. WWW seems to handle this but UnityWebRequest does not. This crash also doesn’t happen in the editor when simulating a memory warning.

We have tried everything from aborting all current requests and yielding until the assets have been cleaned but nothing seems to stop the crash. The only other thing I can think to do is wait for all images to download before running UnloadUnusedAssets and wait until its finished before doing any new requests but this is unworkable because the chances are the app will die from memory pressure first, we need to dump excess memory as soon as we get the call. (this behaviour is essential to our project)

UnityWebRequest gives us many advantages over WWW as well as UnityWebRequest superseding it, so we really want to use it. Can anyone shine any light on the problem? We are in the middle of creating a mini project to repro the bug more effectively for a bug report but maybe someone has seen this before.

We have created a bug report with a repro project for this issue…

https://fogbugz.unity3d.com/default.asp?854618_agto35l3hvc4b525