1

私はCOMオブジェクトを扱うのが初めてで、この件について理解するためにできることを読みましたが、この動作を理解できないようです. 私には、私には理解できない明らかな何かが裏で起こっているのではないかと疑っています。LogParser を使用して IIS ログの処理を自動化し、Excel でレポートを作成しています。最後の列を使用するために作成した PowerShell モジュールの次のコード ブロックから始めました。

$used = $WorkSheet.usedRange
$lastCell = $used.SpecialCells($xlCellTypeLastCell)
if($Axis -eq 'Row'){$tmpLast = $lastCell.Row}
if($Axis -eq 'Column'){$tmpLast = $lastCell.Column}
Release-Ref $used

$WorkSheet は有効なワークシート オブジェクトです。このコード ブロックは、小さなワークシートではうまく機能しましたが、ワークシートのサイズが大きくなるにつれて、実行に時間がかかるようになりました。シートが大きすぎると、完全にぶら下がってしまいます。さらに、使用しようとしていた他のアプリケーションがハングし始め、コンピューターを使用する前に完了するのを待つことになりました。24GBのRAMを搭載したi7でこれを実行しているため、リソースの問題ではありません。PowerShell ISE (2.0) でコードをステップ実行したところ、Release-Ref $used. 大きなワークシートの場合にのみ、その特定の行にハングアップする理由がわかりません。大規模とは、最大 25,000 行と 15 ~ 20 列で定義されます。これは、Excel が処理できるほど大きくありません。Release-Ref 関数は次のとおりです。

function Release-Ref{
[CmdletBinding(DefaultParameterSetName='Single')]
param(
    [Parameter(Mandatory=$true,Position=0,ParameterSetName='Single')]
    [System.__ComObject]$ref,

    [Parameter(Mandatory=$true,Position=0,ParameterSetName='Array')]
    [System.__ComObject[]]$refs,

    [Switch]$Final
)
if($Final){
    [System.GC]::Collect()
    [System.GC]::WaitForPendingFinalizers()
}
if($PSCmdlet.ParameterSetName -eq 'Array'){
    foreach($ref in $refs){
        if($ref -ne $null){
            [System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($ref) `
                | Out-Null
        }
    }
}else{
    if($ref -ne $null){
        [System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($ref) `
            | Out-Null
    }
}
}

この関数をステップ実行すると、遅れることにも気付きましたif($ref -ne $null)問題のコード ブロックと、「COM オブジェクトで 2 つのドットを使用しないでください」という投稿に基づいた関数の両方を構成し、Mike Rosenblom の応答に従って Excel プロセスを適切にクリーンアップする方法を示しました。私はもともと、自動化の最後に Excel プロセスが残っているという問題を抱えていましたが、この原則にできる限り従いました。最終的には Excel を適切に閉じることができましたが、一部のレポートでは実行に 20 ~ 40 分かかりました。

最後に、前のものを置き換える次のコードブロックに移動しました。

$lastCell = $WorkSheet.UsedRange.SpecialCells($xlCellTypeLastCell)
if($Axis -eq 'Row'){$tmpLast = $lastCell.Row}
if($Axis -eq 'Column'){$tmpLast = $lastCell.Column}

現在、2 ドットの原則に違反していますが、これによりハングしていたコールが削除され、レポートが数分で実行されるようになりました。Excel はまだ終了していますが、以前ほどすぐには終了していません。Excel がときどき固執し始めるのではないかと心配していますが、現時点ではパフォーマンスの向上に見合うだけの価値があります。

私の質問は次のとおりです。

  1. コードのそのセクションで 2 ドットの原則に違反しているため、Excel が将来閉じられなくなることを心配する必要がありますか?
  2. また、元のコードで「大きな」ワークシートがパフォーマンスに影響を与えた理由は何ですか?

Release-Ref 関数の呼び出しが遅くなるとは思いもしませんでしたが、ガベージ コレクションのプロセスにあまり詳しくないので、その中に何かがありました。

4

0 に答える 0