{ "id": "171950", "key": "TIMOB-26225", "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": "20214", "description": "", "name": "Release 7.2.1", "archived": false, "released": true, "releaseDate": "2018-08-17" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2018-07-31T18:20:38.000+0000", "created": "2018-07-21T07:41:58.000+0000", "priority": { "name": "High", "id": "2" }, "labels": [ "TableView", "android", "memoryleak" ], "versions": [], "issuelinks": [ { "id": "56697", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "171970", "key": "TIMOB-26239", "fields": { "summary": "Android: Window leak in Ti.UI.currentWindow", "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" } }, "priority": { "name": "Critical", "id": "1" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } }, { "id": "58690", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "171977", "key": "TIMOB-26242", "fields": { "summary": "Android: Change in memory behavior", "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" } }, "priority": { "name": "None", "id": "6" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } } ], "assignee": { "name": "gmathews", "key": "gmathews", "displayName": "Gary Mathews", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2020-08-31T16:14:21.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": "10202", "name": "Android", "description": "Android Platform" } ], "description": "*Summary:*\r\nReplacing a {{TableView}}'s \"data\" array property causes a memory leak where the previous array of rows do not get garbage collected.\r\n\r\n*Steps to reproduce:*\r\n_(Below requires an Android emulator and Chrome web browser to be installed.)_\r\n# Create a \"classic\" Titanium project with the below code.\r\n# Go to the project directory at the command line.\r\n# Enter: {{appc ti build -p android --debug-host /127.0.0.1:51388}}\r\n# Wait for the app to launch. It'll \"hang\" on the splash screen.\r\n# In the log, copy the the \"chrome-devtools://devtools/bundled/inspector.html?...\" URL.\r\n# Open the Chrome browser and paste the copied URL.\r\n# In Chrome, select the \"Memory\" tab.\r\n# Select the \"Allocation instrumentation on timeline\" radio button.\r\n# Click the \"Start\" button.\r\n# Select the \"Sources\" tab.\r\n# Click the \"Resume script execution\" toolbar button in top-right corner. Looks like: [>]\r\n# Wait for the Titanium app to display a TableView.\r\n# Click the \"Reload\" button in the bottom-right corner of the app.\r\n# Click the Android back button.\r\n# In Chrome, select the \"Memory\" tab.\r\n# In Chrome, top-left corner, click the \"Stop recording heap profile\" toolbar button.\r\n# Under the \"Constructor\" column, expand the \"Label\" tree.\r\n# Note that 50 Labels are listed under it. These have not been garbage collected.\r\n\r\n{code:javascript}\r\nfunction createTableData() {\r\n\tvar tableData = [];\r\n\tvar maxIndex = 50;\r\n//var maxIndex = Math.floor(Math.random() * 100) + 1;\r\n\tfor (var index = 1; index <= maxIndex; index++) {\r\n\t\tvar row = Ti.UI.createTableViewRow();\r\n\t\trow.add(Ti.UI.createLabel({ text: \"Row \" + index.toString() }));\r\n\t\ttableData.push(row);\r\n\t}\r\n\treturn tableData;\r\n}\r\n\r\nvar window = Ti.UI.createWindow({ exitOnClose: false });\r\nvar container = Ti.UI.createView({\r\n\twidth: Ti.UI.FILL,\r\n\theight: Ti.UI.FILL,\r\n});\r\nvar tableView = Ti.UI.createTableView({\r\n\tdata: createTableData(),\r\n});\r\ncontainer.add(tableView);\r\nvar reloadButton = Ti.UI.createButton({\r\n\ttitle: \"Reload\",\r\n\tbottom: \"10dp\",\r\n\tright: \"10dp\",\r\n});\r\nreloadButton.addEventListener(\"click\", function(e) {\r\n\tTi.API.info(\"@@@ Reloading table data.\");\r\n\ttableView.data = createTableData();\r\n});\r\ncontainer.add(reloadButton);\r\nwindow.add(container);\r\nwindow.open();\r\n{code}\r\n\r\n*Notes:*\r\n* If a {{TableView}} is garbage collected, then its rows are correctly garbage collected as well. This is only an issue when overwriting the rows via the \"data\" property.\r\n* This is an issue for Alloy since its generated code will replace the {{TableView}} \"data\" array any time the model changes via a \"fetch\", \"destroy\", \"change\", \"add\", \"remove\", or \"reset\" event.\r\n", "attachment": [], "flagged": false, "summary": "Android: TableView leaks memory when overwriting \"data\" property", "creator": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "closedSprints": [ { "id": 1058, "state": "closed", "name": "2018 Sprint 16 SDK", "startDate": "2018-07-29T22:26:06.486Z", "endDate": "2018-08-12T22:26:00.000Z", "completeDate": "2018-08-13T17:38:16.757Z", "originBoardId": 114 }, { "id": 1053, "state": "closed", "name": "2018 Sprint 15 SDK", "startDate": "2018-07-15T21:52:05.453Z", "endDate": "2018-07-29T21:52:00.000Z", "completeDate": "2018-07-29T22:25:11.723Z", "originBoardId": 114 } ], "comment": { "comments": [ { "id": "439515", "author": { "name": "gmathews", "key": "gmathews", "displayName": "Gary Mathews", "active": true, "timeZone": "America/Los_Angeles" }, "body": "master: https://github.com/appcelerator/titanium_mobile/pull/10195\r\n7_3_X: https://github.com/appcelerator/titanium_mobile/pull/10203\r\n7_2_X: https://github.com/appcelerator/titanium_mobile/pull/10197", "updateAuthor": { "name": "gmathews", "key": "gmathews", "displayName": "Gary Mathews", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-07-26T20:37:03.000+0000", "updated": "2018-07-26T20:37:03.000+0000" }, { "id": "439536", "author": { "name": "s.volkov", "key": "s.volkov", "displayName": "Sergey Volkov", "active": true, "timeZone": "Europe/Moscow" }, "body": "You can't simply call [section.releaseViews()|https://github.com/appcelerator/titanium_mobile/pull/10195/files#diff-9f3bae7cb02c715af9fc45d9bc16b732R678] in cleanupSections, because sometimes you will come into this method from [TTVListAdapter.getView|https://github.com/appcelerator/titanium_mobile/blob/7_2_X/android/modules/ui/src/java/ti/modules/titanium/ui/widget/tableview/TiTableView.java#L186] (attention on notice).\r\n[Here|https://gist.github.com/drauggres/4ab66ec8175665ec277384d0b942afc4] is stack trace for this case.", "updateAuthor": { "name": "s.volkov", "key": "s.volkov", "displayName": "Sergey Volkov", "active": true, "timeZone": "Europe/Moscow" }, "created": "2018-07-27T13:36:50.000+0000", "updated": "2018-07-27T13:36:50.000+0000" }, { "id": "439538", "author": { "name": "s.volkov", "key": "s.volkov", "displayName": "Sergey Volkov", "active": true, "timeZone": "Europe/Moscow" }, "body": "Click the \"Reload\" button until app hangs.\r\n{code:javascript}\r\nvar image = \"https://raw.githubusercontent.com/appcelerator/titanium_mobile/\" +\r\n\t\t\"master/.github/logo-titanium.png\";\r\n\r\nfunction createTableData() {\r\n\tvar tableData = [];\r\n\tvar maxIndex = 50;\r\n//var maxIndex = Math.floor(Math.random() * 100) + 1;\r\n\tfor (var index = 1; index <= maxIndex; index++) {\r\n\t\tvar row = Ti.UI.createTableViewRow();\r\n\t\tvar view = Ti.UI.createView({\r\n\t\t\twidth: Ti.UI.FILL,\r\n\t\t\theight: Ti.UI.SIZE,\r\n\t\t\tbackgroundColor: '#555'\r\n\t\t});\r\n\t\tvar url = [image, '?time=', Date.now(), '_', index].join('');\r\n\t\tview.add(Ti.UI.createImageView({\r\n\t\t\twidth: 20,\r\n\t\t\theight: 20,\r\n\t\t\tdefaultImage: image,\r\n\t\t\timage: url\r\n\t\t}));\r\n\t\trow.add(view);\r\n\t\ttableData.push(row);\r\n\t}\r\n\treturn tableData;\r\n}\r\n\r\nvar window = Ti.UI.createWindow({ exitOnClose: false });\r\nvar container = Ti.UI.createView({\r\n\twidth: Ti.UI.FILL,\r\n\theight: Ti.UI.FILL,\r\n});\r\nvar tableView = Ti.UI.createTableView({\r\n\tdata: createTableData(),\r\n});\r\ncontainer.add(tableView);\r\nvar reloadButton = Ti.UI.createButton({\r\n\ttitle: \"Reload\",\r\n\tbottom: \"10dp\",\r\n\tright: \"10dp\",\r\n});\r\nreloadButton.addEventListener(\"click\", function(e) {\r\n\tTi.API.info(\"@@@ Reloading table data.\");\r\n\ttableView.data = createTableData();\r\n});\r\ncontainer.add(reloadButton);\r\nwindow.add(container);\r\nwindow.open();\r\n{code}", "updateAuthor": { "name": "s.volkov", "key": "s.volkov", "displayName": "Sergey Volkov", "active": true, "timeZone": "Europe/Moscow" }, "created": "2018-07-27T14:10:06.000+0000", "updated": "2018-07-27T14:10:06.000+0000" }, { "id": "439655", "author": { "name": "lchoudhary", "key": "lchoudhary", "displayName": "Lokesh Choudhary", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Verified the fix in SDK's 7.4.0.v20180801012329, 7.3.0.v20180731101200 & 7.2.1.v20180726150551.\r\nClosing.", "updateAuthor": { "name": "lchoudhary", "key": "lchoudhary", "displayName": "Lokesh Choudhary", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-08-01T18:18:01.000+0000", "updated": "2018-08-01T18:18:01.000+0000" } ], "maxResults": 6, "total": 6, "startAt": 0 } } }