Office JS setDataAsync函数内存泄漏

时间:2017-03-20 16:48:38

标签: excel memory-leaks ms-office office-js office-addins

在Excel 2016中的office js的共享API中使用Async函数时,会导致内存泄漏,特别是调用binding.setDataAsnyc,它永远不会释放写入的数据。(泄漏发生在 Internet Explorer 进程在excel中运行插件(它是32位版本))。

示例:

//1 Miliion row by 10 columns data parsed from a csv usually in chunks
var data = [];
var i,j;
for (i=0; i<1000000; i++) {
    row = [];
    for(j=0; j<10; j++) {
        row.push("data" + i + "" + j);
    }
    data.push(row);
}
var limit = 10000;
var next = function (step) {
    var columnLetter = getExcelColumnName(data[0].length);
    var startRow = step * limit + 1;
    var endRow = start + limit;
    if (data.length < startRow)
        return;
    var values = data.slice(startRow - 1, endRow - 1);
    var range = "A" + startRow + ":" + columnLetter + "" + endRow;
    Office.context.document.bindings.addFromNamedItemAsync(range,
        Office.CoercionType.Matrix, { id: "binding" + step },
        function (asyncResult) {
            if (asyncResult.status == "failed") {
                console.log('Error: ' + asyncResult.error.message);
                return;
            }

            Office.select("bindings#binding" + step).setDataAsync(values,
                {
                    coercionType: Office.CoercionType.Matrix
                }, function (asyncResult) {
                    //Memory keeps Increasing on this callback
                    if (asyncResult.status == Office.AsyncResultStatus.Failed) {
                        console.log("Action failed with error: " + asyncResult.error.message);
                        return;
                     }

                     next(step++);
                });
        });
    }

next(0);

我尝试在setDataAsync之后释放每个绑定,但仍然存在内存。回收内存的唯一方法是重新加载插件。

我尝试了另一种为范围分配值的方法:

range.values = values;

它没有泄漏但是需要3倍于setDataAsync(对于1M行乘以10列大约210秒),而setDataAsync大约需要70秒,但当然泄漏并消耗1.1该请求中的GB内存。

我也试过table.rows.add(null, values);,但表现得更差。

我在没有setdataAsync的情况下测试了相同的代码(立即调用)并且没有发生内存泄漏。

有没有人遇到过这种情况? 反正它是否有释放那个记忆? 如果没有另外的方法来填充Excel中的大量数据,除了这三种方法也很快?

2 个答案:

答案 0 :(得分:0)

添加绑定确实会增加内存消耗 - 但只是调用setDataAsync肯定不应该(或者至少不是超出预期,或者通过手动将数据复制粘贴到工作表中)会是)。

有一点需要澄清:当你说:

  

我也试过了table.rows.add(null, values),但效果更差。

我假设您的意思是使用Excel.run(function(context) { ... });执行备用Office 2016 wave-of-API语法?关于perf,我可以跟进,但是我很好奇当你使用新的API语法时是否发生了内存泄漏。

FWIW,有一个近期未来的API将允许您在设置值时暂停计算 - 这应该可以提高性能。但我确实想知道我们是否能找出你指出的两个问题:setDataAsyncrange.values电话上的内存泄漏。

如果您可以从回答上述问题开始(即使在range.values中是否发生同样的泄漏),这将有助于缩小问题范围,然后我会跟进团队。

谢谢!

答案 1 :(得分:0)

我发现有一个布尔window.Excel._RedirectV1APIs可以设置为true,使setDataAsync使用新的API。如果

,应自动设置

window.Office.context.requirements.isSetSupported("RedirectV1Api")

返回true但不知何故该要求未设置,但如果您手动设置

则它可以正常工作

window.Excel._RedirectV1APIs = true

但它仍然比原始setDataAsync慢得多,但比range.values手动方法略快(对于1M行乘以10列,160s对180s)并且不会导致内存泄漏。

另外,我发现内存泄漏发生在id {71(window.external.Execute(id, params, callback))的setDataAsnyc函数之后,并且在从该函数调用回调时,似乎内存泄漏在某种程度上发生在/中Excel本身的外部代码(虽然内存泄漏是在Internet Explorer的过程中)。如果你短路并直接调用回调而不是window.external.Execute没有发生内存泄漏,当然,也没有设置数据。