{ "id": "63798", "key": "TIMOB-3166", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "11244", "name": "Release 1.7.0", "archived": true, "released": true, "releaseDate": "2011-06-13" }, { "id": "11246", "name": "Sprint 2011-11", "archived": true, "released": true, "releaseDate": "2011-03-21" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2011-05-11T17:13:03.000+0000", "created": "2011-04-15T03:38:32.000+0000", "priority": { "name": "Medium", "id": "3" }, "labels": [ "ios", "klist", "memory" ], "versions": [], "issuelinks": [], "assignee": { "name": "rseagraves", "key": "rseagraves", "displayName": "Reggie Seagraves", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2011-05-11T17:13:03.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10206", "name": "iOS", "description": "iOS Platform" } ], "description": "{html}

We are using Titanium 1.6RC1 with Developer 1.2.2 and think we\nhave found a significant memory leak when displaying remote\nthumbnails in a tableview. Below is the code to reproduce.

\n

Upon running the code, just attach to the process using XCode\nInstruments. Then click the \"Photos\" button to bring up the grid of\nphotos, then click back to close the window. Continue to do this\nover and over again and you will see the living memory allocations\ncontinue to increase to extremely high levels.

\n

Why doesn't closing a window free up all it's memory usage? I\ncome from the Objective-C world and have created this same screen\nnatively with no memory leaks. Am I missing something in our\njavascript code? This is a showstopper for us if we cannot find a\nsolution.

\n

Thanks!

\n

Brian

\n
\nvar tabGroup = Titanium.UI.createTabGroup({id:'tabGroup1'});\n \nwin = Titanium.UI.createWindow({id:'win1',backgroundColor:'#fff'});\nvar button = Ti.UI.createButton({title:'Photos',width:100, height:100});\n \nbutton.addEventListener('click', function() {\n    var photosWindow = Titanium.UI.createWindow({fullscreen:false});\n    var tableView = Ti.UI.createTableView({\n        separatorStyle:Ti.UI.iPhone.TableViewSeparatorStyle.NONE\n    });\n    photosWindow.add(tableView);\n \n    tab1.open(photosWindow, {animated:true});\n \n    var xhr = Titanium.Network.createHTTPClient();\n    xhr.onload = function() {\n        var list = JSON.parse(this.responseText).List;\n        var rowData = [];\n        for (var i = 0,count = list.length; i < count; i += 4) {\n            var row = Ti.UI.createTableViewRow({\n                height:'auto',\n                selectedBackgroundColor: '#fff',\n                backgroundSelectedColor: '#fff',\n                className:'tvRow'\n            }),imgDimensions = 80;\n \n \n            var offSet = 0;\n            for (var j = 0; j < 4; j++) {\n                var photo = list[i + j];\n                if (photo) {\n                    var photoView = Ti.UI.createImageView({\n                        top:0,\n                        left:offSet,\n                        height:imgDimensions,\n                        width:imgDimensions,\n                        image:photo.ThumbnailUrl\n                    });\n                    row.add(photoView);\n                    offSet += imgDimensions;\n                }\n            }\n            rowData.push(row);\n        }\n        tableView.setData(rowData);\n    };\n    var url = \"http://idancemobile.com/event/e2e530/api/2.0/images/0\";\n    xhr.open(\"GET\", url);\n    xhr.send();\n});\n \nwin.add(button);\n \nvar tab1 = Titanium.UI.createTab({\n    id:'tab1',\n    window:win\n});\n \ntabGroup.addTab(tab1);\n \ntabGroup.open();\n
{html}", "attachment": [], "flagged": false, "summary": "significant memory leak with thumbnails in tableview", "creator": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "comment": { "comments": [ { "id": "130205", "author": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "body": "{html}

Memory management is a priority for 1.7.0. Examples like this\nhelp a great deal, especially since they include some information\nabout the original data being used.

{html}", "updateAuthor": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-04-15T03:38:33.000+0000", "updated": "2011-04-15T03:38:33.000+0000" }, { "id": "130206", "author": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "body": "{html}

I created another example that better displays the image memory\nissue in the tableview. When running the code below just keep\nhitting \"Refresh\" and you will see the \"available memory\" as the\ntitle. Eventually it gets so low that it crashes.

\n
\nvar win = Titanium.UI.createWindow({fullscreen:false,backgroundColor:'#fff',title:Ti.Platform.availableMemory});\nvar button = Ti.UI.createButton({title:'Refresh',width:40, height:30});\n\nvar tableView = Ti.UI.createTableView({\n    separatorStyle:Ti.UI.iPhone.TableViewSeparatorStyle.NONE\n});\nwin.add(tableView);\n\nbutton.addEventListener('click', function() {\n    load();\n});\n\nwin.rightNavButton = button;\n\nvar navGroup = Ti.UI.iPhone.createNavigationGroup({\n    window:win\n});\n\nvar main = Ti.UI.createWindow();\nmain.add(navGroup);\nmain.open();\n\nload();\n\nfunction load() {\n    var xhr = Titanium.Network.createHTTPClient();\n    xhr.onload = function() {\n        var list = JSON.parse(this.responseText).List;\n        var rowData = [];\n        for (var i = 0,count = list.length; i < count; i += 4) {\n            var row = Ti.UI.createTableViewRow({\n                height:'auto',\n                selectedBackgroundColor: '#fff',\n                backgroundSelectedColor: '#fff',\n                className:'tvRow'\n            }),imgDimensions = 80;\n\n\n            var offSet = 0;\n            for (var j = 0; j < 4; j++) {\n                var photo = list[i + j];\n                if (photo) {\n                    var photoView = Ti.UI.createImageView({\n                        top:0,\n                        left:offSet,\n                        height:imgDimensions,\n                        width:imgDimensions,\n                        image:photo.ThumbnailUrl\n                    });\n                    row.add(photoView);\n                    offSet += imgDimensions;\n                }\n            }\n            rowData.push(row);\n        }\n        tableView.setData(rowData);\n        win.title = Ti.Platform.availableMemory;\n    };\n    var url = \"http://api.plixi.com/api/tpapi.svc/json/photos\";\n    xhr.open(\"GET\", url);\n    xhr.send();\n}\n
{html}", "updateAuthor": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-04-15T03:38:33.000+0000", "updated": "2011-04-15T03:38:33.000+0000" }, { "id": "130207", "author": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "body": "{html}

Sorry for so many code posts :) But I think I have the perfect\nexample of what is going wrong....please use the following instead\nof the previous two :) If you click the \"Launch\" button and then\nclick the back button over and over again you will see the\n\"available memory\" continue to lower and eventually crash. I really\nthink that closing the photosWindow should release all the memory\nit uses, rather than leaking. Also please test this using the real\ndevice and NOT the simulator.

\n
\nvar xhr = Titanium.Network.createHTTPClient();\n\nvar launchWindow = Titanium.UI.createWindow({fullscreen:false,backgroundColor:'#fff'});\nlaunchWindow.addEventListener('focus', function() {\n    launchWindow.title = Ti.Platform.availableMemory;\n});\n\nvar launchButton = Ti.UI.createButton({title:'Launch',width:100, height:100});\nlaunchWindow.add(launchButton);\n\nlaunchButton.addEventListener('click', function() {\n    var photosWindow = Titanium.UI.createWindow({fullscreen:false,backgroundColor:'#fff',title:Ti.Platform.availableMemory});\n    var refreshButton = Ti.UI.createButton({title:'Refresh',width:40, height:30});\n\n    var tableView = Ti.UI.createTableView({\n        separatorStyle:Ti.UI.iPhone.TableViewSeparatorStyle.NONE\n    });\n    photosWindow.add(tableView);\n\n    refreshButton.addEventListener('click', function() {\n        load();\n    });\n\n    photosWindow.rightNavButton = refreshButton;\n\n    photosWindow.addEventListener('close', function() {\n        photosWindow.close();\n        launchWindow.title = Ti.Platform.availableMemory;\n    });\n\n    navGroup.open(photosWindow, {animate:true});\n    load();\n    function load() {\n        xhr.onload = function() {\n            var list = JSON.parse(this.responseText).List;\n            var rowData = [];\n            for (var i = 0,count = list.length; i < count; i += 4) {\n                var row = Ti.UI.createTableViewRow({\n                    height:'auto',\n                    selectedBackgroundColor: '#fff',\n                    backgroundSelectedColor: '#fff',\n                    className:'tvRow'\n                }),imgDimensions = 80;\n\n\n                var offSet = 0;\n                for (var j = 0; j < 4; j++) {\n                    var photo = list[i + j];\n                    if (photo) {\n                        var photoView = Ti.UI.createImageView({\n                            top:0,\n                            left:offSet,\n                            height:imgDimensions,\n                            width:imgDimensions,\n                            image:photo.ThumbnailUrl\n                        });\n                        row.add(photoView);\n                        offSet += imgDimensions;\n                    }\n                }\n                rowData.push(row);\n            }\n            tableView.setData(rowData);\n            photosWindow.title = Ti.Platform.availableMemory;\n        };\n        var url = \"http://api.plixi.com/api/tpapi.svc/json/photos\";\n        xhr.open(\"GET\", url);\n        xhr.send();\n    }\n});\n\nvar navGroup = Ti.UI.iPhone.createNavigationGroup({\n    window:launchWindow\n});\n\nvar main = Ti.UI.createWindow();\nmain.add(navGroup);\nmain.open();\n
{html}", "updateAuthor": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-04-15T03:38:33.000+0000", "updated": "2011-04-15T03:38:33.000+0000" }, { "id": "130208", "author": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "body": "{html}

I wanted to mention that the last code post is using suggestions\nmade by folks in the Q&Q forum...to call photosWindow.close on\nthe close event and to use a single HttpClient.

\n

Also when the memory gets really low I see things like this in\nthe debug console in XCode:

\n

[INFO] Due to memory conditions, 0 of 3244\nimages were unloaded from cache.

\n

Why would it unload 0 images if it got a memory warning? Seems\nlike this is a big issue too.

{html}", "updateAuthor": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-04-15T03:38:33.000+0000", "updated": "2011-04-15T03:38:33.000+0000" }, { "id": "130209", "author": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "body": "{html}

Once again, not picking up the github commit.

\n

TESTING:

\n

There are two levels of testing that need to be conducted.

\n

INSTRUMENTS

\n\n

W/OUT INSTRUMENTS

\n
{html}", "updateAuthor": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-04-15T03:38:36.000+0000", "updated": "2011-04-15T03:38:36.000+0000" }, { "id": "130210", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "{html}

(from [10c2ba87ab69e00ee963e38bd272ab5c8438aec4])\n[#3166] Properly handle the case where\nmodalDelegate is 'self', which is pretty much always. \nhttps://github.com/appcelerator/titanium_mobile/commit/10c2ba87ab69...

{html}", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2011-04-15T03:38:36.000+0000", "updated": "2011-04-15T03:38:36.000+0000" }, { "id": "130211", "author": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "body": "{html}

Would it be possible to back port this to 1.6.x? We cannot wait\nuntil the end of May for 1.7

{html}", "updateAuthor": { "name": "brian", "key": "brian", "displayName": "Brian", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-04-15T03:38:36.000+0000", "updated": "2011-04-15T03:38:36.000+0000" }, { "id": "130212", "author": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "body": "{html}

You can just get a CI build or pull directly from github. This\nwill not be backported to 1.6.x.

{html}", "updateAuthor": { "name": "stephentramer", "key": "stephentramer", "displayName": "Stephen Tramer", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-04-15T03:38:36.000+0000", "updated": "2011-04-15T03:38:36.000+0000" }, { "id": "133468", "author": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "body": "No longer able to reproduce with iPhone 4, iOS 4.3.3. KS 1.7.0, build 1.7.0.879871b. Used the 3rd added code, but used instruments to monitor memory. Opened the thumbnail view repeatedly for over 5 mins. Memory leak not detected. Closing.", "updateAuthor": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-05-11T17:13:03.000+0000", "updated": "2011-05-11T17:13:03.000+0000" } ], "maxResults": 9, "total": 9, "startAt": 0 } } }