Quantcast
Channel: Questions in topic: "xcode"
Viewing all articles
Browse latest Browse all 1047

IOS memory leak because of WWW object

$
0
0
Hi there, I have a nifty memory leak when I run my project on the IOS platform. I have checked it using instruments leak tool and debug using Xcode 6. In some cases it looks like the WWW object is never disposed. ------------------------------------------------------------------- I°) Here is the part of code that handle sending WWW requests: private void issueRequestWithoutQueuing(string url, Dictionary parameters = null, Callback successCallback = null, Callback apiFailureCallback = null, Callback layerFailureCallback = null, bool showSpinner = false) { QueuedWWWObject queueWWW = new QueuedWWWObject(); queueWWW.url = url; queueWWW.successCB = successCallback; queueWWW.apiFailureCB = apiFailureCallback; queueWWW.layerFailureCB = layerFailureCallback; if (parameters != null) { queueWWW.parameters = parameters; } issueRequest(queueWWW, showSpinner); } private void issueRequest(QueuedWWWObject queueWWW, bool showSpinner = false) { numberRequestInProgress ++; WWW www; if (queueWWW.parameters != null && queueWWW.parameters.Count != 0) { WWWForm form = new WWWForm(); foreach (KeyValuePair pair in queueWWW.parameters) { form.AddField(pair.Key, pair.Value); } www = new WWW(queueWWW.url, form); } else { www = new WWW(queueWWW.url); } NetworkManager.instance.StartCoroutine(WaitForRequest(www, queueWWW, queueWWW.successCB, queueWWW.apiFailureCB, queueWWW.layerFailureCB)); } We are waiting for request until we receive either that the request is done, there has been an error, or the request has timed out private IEnumerator WaitForRequest(WWW www, Callback successCallback = null, Callback apiFailureCallback = null, Callback layerFailureCallback = null) { int startLaunchRequestTime = ServerTime.instance.getRealGameTime(); while (!www.isDone && www.error == null && ((ServerTime.instance.getRealGameTime() - startLaunchRequestTime) < REQUEST_TIMEOUT)) { yield return www; } LaunchCallback cb = new LaunchCallback(); cb.www = www; cb.successCB = successCallback; cb.apiFailureCB = apiFailureCallback; cb.layerFailureCB = layerFailureCallback; if ((ServerTime.instance.getRealGameTime() - startLaunchRequestTime) >= REQUEST_TIMEOUT) { cb.timeOutError = true; } _launchCallbacks.Add(cb); } ------------------------------------------------------------------- II°) And then, in the update function, where we request the results for the launchcallback, handle the callbacks, and dispose the WWW object: public void update() { int len = _launchCallbacks.Count; List callbackToDelete = new List(); for (int i=0; i successCallback, Callback apiFailureCallback , Callback layerFailureCallback, bool timeOutError) { // handles success/ failure callbacks, not relevant here numberRequestInProgress --; } ------------------------------------------------------------------- III°) The LauncCcallback class is just a container for the WWW object and its callbacks: public class LaunchCallback { public Callback successCB; public Callback apiFailureCB; public Callback layerFailureCB; public WWW www; public bool hasTransaction; public bool timeOutError = false; public void dispose() { Debug.Log (" DISPOSING WWW object " + www.url ); www.Dispose(); successCB = null; apiFailureCB = null; layerFailureCB = null; } } ------------------------------------------------------------------- When I run the project on IOS, I get the debug output of DISPOSING WWW object " + www.url, but the leak instrument tells me that the issueRequest function has leaked several strings, dictionary etc etc, as if the WWW has not been disposed: http://imgur.com/RWBbYwH When I put a breakpoint in Xcode, we pass in the destroy function for every request: extern "C" void UnityDestroyWWWConnection(void* connection) { UnityWWWConnectionDelegate* delegate = (UnityWWWConnectionDelegate*)connection; [delegate cleanup]; [delegate release]; } which calls this: - (void)cleanup { [_connection cancel]; _connection = nil; [_data release]; _data = nil; } I really don't know what's going on, because I do pass in the dispose function of the launchcallback. Is there any references that could lead the WWW object to not be disposed? PS: I am using unity 4.5.5 & monodevelop 4.0.1 Many thanks, Down ------------------------------------------------------------------------------------------------------------------- UPDATE 1: A little update: After reviewing the code generated by unity in xcode and analyzing it: xcode tells me that there is a potential leak in the WWWConnection.mm, particulary here, the delegate.connection is never cleaned: extern "C" void* UnityStartWWWConnectionGet(void* udata, const void* headerDict, const char* url) { UnityWWWConnectionDelegate* delegate = [UnityWWWConnectionDelegate newDelegateWithCStringURL:url udata:udata]; NSMutableURLRequest* request = [UnityWWWConnectionDelegate newRequestForHTTPMethod:@"GET" url:delegate.url headers:(NSDictionary*)headerDict]; delegate.connection = [NSURLConnection connectionWithRequest:request delegate:delegate]; return delegate; } the same occurs for POST methods: extern "C" void* UnityStartWWWConnectionPost(void* udata, const void* headerDict, const char* url, const void* data, unsigned length) { UnityWWWConnectionDelegate* delegate = [UnityWWWConnectionDelegate newDelegateWithCStringURL:url udata:udata]; NSMutableURLRequest* request = [UnityWWWConnectionDelegate newRequestForHTTPMethod:@"POST" url:delegate.url headers:(NSDictionary*)headerDict]; [request setHTTPBody:[NSData dataWithBytes:data length:length]]; [request setValue:[NSString stringWithFormat:@"%d", length] forHTTPHeaderField:@"Content-Length"]; delegate.connection = [NSURLConnection connectionWithRequest:request delegate:delegate]; return delegate; } Which correlates nicely with what I see: http://imgur.com/vIdeg54 I don't really know what to do, as it looks like its related to the unity code. Any help would be appreciated. ------------------------------------------------------------------------------------------------------------------------------------------ UPDATE 2 I have a similar leak when I call this function: private void OnEnable() { StartCoroutine(doGet(facebookURL, onGetFacebookAvatar)); } public IEnumerator doGet(string url, Callback callback = null) { using (WWW www = new WWW(url)) { yield return www; if (callback != null) { callback(www); callback = null; } } } private void onGetFacebookAvatar(WWW result) { if (!string.IsNullOrEmpty (result.error)) { ErrorManager.instance.logWarning (ErrorManager.ERROR_FACEBOOK_API, "Get facebook avatar failed : " + result.error, "AvatarBehaviour"); } else { Texture2D texture = new Texture2D(frame.width-20, frame.height-20); if (!_facebookAvatar.ContainsKey(_userID)) { // Never use www.texture as it cause memory leak (WWW object is never released) result.LoadImageIntoTexture(texture); _facebookAvatar.Add(_userID, texture); } avatarTexture.mainTexture = texture; avatarTexture.width = frame.width - 20; avatarTexture.height = frame.height - 20; NGUITools.SetActiveSelf(avatarSprite.gameObject, false); NGUITools.SetActiveSelf(avatarTexture.gameObject, true); } } see http://imgur.com/vIdeg54 --------------------------------------------------------------------------------------------------------------- UPDATE 3: After some investigation, adding the line: [request release]; here extern "C" void* UnityStartWWWConnectionGet(void* udata, const void* headerDict, const char* url) { UnityWWWConnectionDelegate* delegate = [UnityWWWConnectionDelegate newDelegateWithCStringURL:url udata:udata]; NSMutableURLRequest* request = [UnityWWWConnectionDelegate newRequestForHTTPMethod:@"GET" url:delegate.url headers:(NSDictionary*)headerDict]; delegate.connection = [NSURLConnection connectionWithRequest:request delegate:delegate]; [request release]; return delegate; } Does helps, but still some leak, maybe because what's inside the request is not fully released (string and stuff), still investigating

Viewing all articles
Browse latest Browse all 1047

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>