.NET和CreateObject,COM对象使用的是哪个内存?

3
我有一个使用VB.NET编写的应用程序,使用CreateObject调用Excel并将大量数据导入其中。我们遇到了内存不足的异常,并且此时该应用程序通常会占用1GB的内存。但是,我不能让所有数字加起来。
以下是将数据传递给Excel的方式:
    worksheet_object.Range("A1").Resize(rows, cols).Value = an_array

这个应用程序大约有400MB的屏幕数据(数据网格),当它崩溃时,尽管Excel和CSV只有200MB和68MB,但它使用了额外的600MB。我意识到内存数组可能会更大,但是除非Excel以某种方式使用我的应用程序内存,否则如何消耗600MB传递数据给Excel?
我试图找出Excel是否通过CreateObject在自己的内存空间中运行还是使用我的应用程序内存空间,但是一无所获。ProcessExplorer将它们显示为单独的进程,所以我不知道该怎么想。
我们发现将应用程序作为64位而不是32位运行可以解决问题,但并非所有客户都拥有64位的Office。
因此,我的问题是:那一行代码如何使用600MB,并且有没有更好的方法将数据传递给Excel。

Excel只在自己的进程中分配内存。您需要注意进程中的GC并查看它是否收集得足够频繁。当您仅进行Interop调用时,很容易永远不触发收集。这可能会导致RCWs增加。使用Perfmon.exe查看.NET GC性能计数器,最好使用内存分析器。对策是定期强制进行GC,例如每N行。 - Hans Passant
你没有说有多少行和列?(每个Excel单元格可能会使用大量内存)。但也许你正在分割可用的2GB地址空间:你尝试过分块处理吗? - Charles Williams
大约有200,000行,可能有50列。传递的数组有约9.7百万个单元格。我找不到获取其内存大小的方法。我想我可以使用二进制序列化程序并将其写入文件。 - Mark Leavesley
据推测,该操作意味着要复制许多数组。假设只有数字的话,那么这样大小的工作表将占用超过200MB的内存:等效的对象数组可能差不多也需要同样大小的内存,而且通过COM互操作进行处理可能至少需要再复制一次甚至两次。内存碎片可能意味着大块连续内存的请求得不到满足。如果您使用10个较小的块来执行此操作,则可能在32位模式下运行。 - Charles Williams
1个回答

0

我敢打赌,这一行代码运行起来也需要一些时间,9.7M个单元格!?但无论如何,有两个问题:

1:那一行代码怎么会用到600MB的内存(我猜你是指字节(Byte),而不是比特(bit))

我认为你已经通过9.7M个单元格回答了这个问题。每个单元格只有61个字节。我想你可能有一些字符串。每个字符串使用几个字节,加上每个字符2个字节。带小数点的数字占用16个字节。更不用说,数组还有一定的大小,以处理它的信息。请参见此图表,了解VB中数据占用的大致情况。2012 VB Data Types 我刚刚发现一个惊人的事实,因为我很久没有看过这张图表,那就是通过转换到64位操作系统,它实际上应该占用更多的内存。幸运的是,64位可以处理更多的内存。

2:有没有更好的方法将数据传递给Excel。

你可以尝试使用OLEDB ACE驱动程序来处理Excel文件。它更快,不需要计算机上安装EXCEL,这是一个很大的优点。
这篇文章虽然有些年头,但仍然相关且非常有用。如果需要新版本Excel的连接字符串,请参考ConnectionStrings.com。而如果想使用ADO.NET来检索和修改Excel工作簿中的记录,请查看如何使用ADO.NET在Visual Basic .NET中检索和修改Excel工作簿中的记录

我们最终选择了64位路线为这个客户提供服务,但我认为这是一个问题,将再次出现,因此这些链接对于寻找解决方案应该非常有用。谢谢。 - Mark Leavesley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接