【问题标题】:C# Excel OutOfMemory exception caused by inserting to a range插入范围导致的 C# Excel OutOfMemory 异常
【发布时间】:2020-06-15 00:14:30
【问题描述】:

我一直在从事一个相当复杂的 C# VSTO 项目,该项目在 Excel 中做了很多不同的事情。但是,我最近偶然发现了一个我不知道如何解决的问题。恐怕把整个项目放在这里会使我的问题过于复杂并使每个人都感到困惑,所以这是问题所在:

//this is a simplified version of Range declaration which I am 100% confident in
Range range = worksheet.Range[firstCell, lastCell] 

range.Formula = array; 
//where array is a object[,] which basically contains only strings and also works perfeclty fine

最后一行应该将 [,] 数组插入到以前用于较小的 Excel 书籍的 Excel 范围内,但现在对于带有 System.OutOfMemoryException: Insufficient memory to continue the execution of the program 的较大书籍会崩溃,我不知道为什么,因为它使用了可以使用其中一个维度长达 500 多个元素的数组,而现在它会因元素少于 400 个的数组而崩溃。此外,崩溃时的 RAM 使用量约为 1.2GB,我知道这个项目能够在大约 3GB 的 RAM 使用量下完美运行。

我尝试了以下方法:逐行插入此数组,然后逐个单元格地插入它,在每次插入行或单元格之前调用 GC.Collect() 但它仍然会因System.OutOfMemoryException 而崩溃。

因此,我将不胜感激在解决此问题或确定错误可能隐藏的位置方面的任何帮助,因为我无法理解为什么它拒绝为长度较小的数组工作(但可能内容稍大)在 1.2GB 的 RAM 使用水平上,它是过去处理的 1/3。谢谢!

编辑

我在cmets中被告知上面的代码可能太稀疏了,所以这里有一个更详细的版本(我希望它不会太混乱):

List<object[][]> controlsList = new List<object[][]>();
// this list is filled with a quite long method calling a lot of other functions
// if other parts look fine, I guess I'll have to investigate it

int totalRows = 1;

foreach (var control in controlsList)
{
    if (control.Length == 0)
        continue;

    var range = worksheet.GetRange(totalRows + 1, 1, totalRows += control.Length, 11);
    //control is an object[n][11] so normally there are no index issues with inserting
    range.Formula = control.To2dArray();
}

//GetRange and To2dArray are extension methods
public static Range GetRange(this Worksheet sheet, int firstRow, int firstColumn, int lastRow, int lastColumn)
{
    var firstCell = sheet.GetRange(firstRow, firstColumn);
    var lastCell = sheet.GetRange(lastRow, lastColumn);

    return (Range)sheet.Range[firstCell, lastCell];
}

public static Range GetRange(this Worksheet sheet, int row, int col) => (Range)sheet.CheckIsPositive(row, col).Cells[row, col];

public static T CheckIsPositive<T>(this T returnedValue, params int[] vals)
{
    if (vals.Any(x => x <= 0))
        throw new ArgumentException("Values must be positive");

    return returnedValue;
}

public static T[,] To2dArray<T>(this T[][] source)
{
    if (source == null)
        throw new ArgumentNullException();

    int l1 = source.Length;
    int l2 = source[0].Length(1);

    T[,] result = new T[l1, l2];

    for (int i = 0; i < l1; ++i)
        for (int j = 0; j < l2; ++j)
            result[i, j] = source[i][j];

    return result;
}

【问题讨论】:

  • firstCelllastCell 的值是多少? array的尺寸是多少?锯齿状数组中有哪些类型的对象?代码似乎有点太稀疏,无法排除值太大并因此导致问题。
  • 通常,找出导致此类问题的最快方法是使用分析器并在堆运行时查看它。如果你有企业版,它有一个内置的分析器,如果没有的话,可以使用第三方分析器。另请注意,您无法比较调试和发布行为。正如@MartinCostello 所说,如果没有更多关于范围到底有多大以及数组中有什么的详细信息,很难提供更多信息。
  • 您是否打算将 Array 的内容插入到指定 Range 中的每个单元格中?
  • @MartinCostello 我在编辑中提供了与问题相关的代码,谢谢!希望问题不在于列表填充方法(我没有发布),因为它不会在那里崩溃,并且由于其复杂性而很难调查。
  • @MikeJ 在堆中有什么需要特别注意的吗?我对内存处理不太熟悉,所以如果您指出可能导致内存泄漏的原因,我将不胜感激(我在编辑中添加了一些代码),谢谢!

标签: c# excel memory out-of-memory vsto


【解决方案1】:

我不是 100% 确定我正确地计算出来了,但问题似乎在于 Interop.Excel/Excel 限制和我尝试插入的公式的长度:只要长度接近 8k 个字符,即接近公式内容的 Excel 限制时,System.OutOfMemoryException 会弹出。当我选择放弃冗长的公式时,程序开始正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 2015-06-04
    相关资源
    最近更新 更多