[TIMOB-26225] Android: TableView leaks memory when overwriting "data" property
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | High |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2018-07-31T18:20:38.000+0000 |
Affected Version/s | n/a |
Fix Version/s | Release 7.2.1 |
Components | Android |
Labels | TableView, android, memoryleak |
Reporter | Joshua Quick |
Assignee | Gary Mathews |
Created | 2018-07-21T07:41:58.000+0000 |
Updated | 2020-08-31T16:14:21.000+0000 |
Description
*Summary:*
Replacing a Enter:
TableView
's "data" array property causes a memory leak where the previous array of rows do not get garbage collected.
*Steps to reproduce:*
_(Below requires an Android emulator and Chrome web browser to be installed.)_
Create a "classic" Titanium project with the below code.
Go to the project directory at the command line.
Enter: appc ti build -p android --debug-host /127.0.0.1:51388
Wait for the app to launch. It'll "hang" on the splash screen.
In the log, copy the the "chrome-devtools://devtools/bundled/inspector.html?..." URL.
Open the Chrome browser and paste the copied URL.
In Chrome, select the "Memory" tab.
Select the "Allocation instrumentation on timeline" radio button.
Click the "Start" button.
Select the "Sources" tab.
Click the "Resume script execution" toolbar button in top-right corner. Looks like: [>]
Wait for the Titanium app to display a TableView.
Click the "Reload" button in the bottom-right corner of the app.
Click the Android back button.
In Chrome, select the "Memory" tab.
In Chrome, top-left corner, click the "Stop recording heap profile" toolbar button.
Under the "Constructor" column, expand the "Label" tree.
Note that 50 Labels are listed under it. These have not been garbage collected.
function createTableData() {
var tableData = [];
var maxIndex = 50;
//var maxIndex = Math.floor(Math.random() * 100) + 1;
for (var index = 1; index <= maxIndex; index++) {
var row = Ti.UI.createTableViewRow();
row.add(Ti.UI.createLabel({ text: "Row " + index.toString() }));
tableData.push(row);
}
return tableData;
}
var window = Ti.UI.createWindow({ exitOnClose: false });
var container = Ti.UI.createView({
width: Ti.UI.FILL,
height: Ti.UI.FILL,
});
var tableView = Ti.UI.createTableView({
data: createTableData(),
});
container.add(tableView);
var reloadButton = Ti.UI.createButton({
title: "Reload",
bottom: "10dp",
right: "10dp",
});
reloadButton.addEventListener("click", function(e) {
Ti.API.info("@@@ Reloading table data.");
tableView.data = createTableData();
});
container.add(reloadButton);
window.add(container);
window.open();
*Notes:*
* 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.
* 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.
master: https://github.com/appcelerator/titanium_mobile/pull/10195 7_3_X: https://github.com/appcelerator/titanium_mobile/pull/10203 7_2_X: https://github.com/appcelerator/titanium_mobile/pull/10197
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). [Here](https://gist.github.com/drauggres/4ab66ec8175665ec277384d0b942afc4) is stack trace for this case.
Click the "Reload" button until app hangs.
Verified the fix in SDK's 7.4.0.v20180801012329, 7.3.0.v20180731101200 & 7.2.1.v20180726150551. Closing.