2012-04-16 9 views
4

私はネストされたforループで自分のアプリケーションにメモリの問題があり、改善方法を見つけることができません。私はlinqを使ってみましたが、メモリリークがまだあるので、内部的には同じです。ネストされたループを最適化する

EDIT:私が要求されたように、私は私の問題についての詳細を提供します。

私はすべての顧客(約400.000)をLuceneのドキュメントストアに登録しています。各顧客は複数の代理店に存在することができ、そのうちのいくつかは200-300の代理店に存在することができます。

「グローバル」顧客インデックスからすべての顧客を検索し、各代理店ごとに個別のインデックスを作成する必要があります。各機関のインデックスに適用する必要があるビジネスルールとセキュリティルールがありますので、現在、私のすべての代理店に対して単一の顧客インデックスを維持する余裕はありません。

int numDocuments = 400000; 

// Get a Lucene Index Searcher from an Index Factory 
IndexSearcher searcher = SearcherFactory.Instance.GetSearcher(Enums.CUSTOMER); 

// Builds a query that gets everything in the index 
Query query = QueryHelper.GetEverythingQuery(); 
Filter filter = new CachingWrapperFilter(new QueryWrapperFilter(query)); 

// Sorts by Agency Id 
SortField sortField = new SortField("AgencyId, SortField.LONG); 
Sort sort = new Sort(sortField); 

TopDocs documents = searcher.Search(query, filter, numDocuments, sort); 

for (int i = 0; i < numDocuments; i++) 
{ 
    Document document = searcher.Doc(documents.scoreDocs[i].doc); 

    // Builds a customer object from the lucene document 
    Customer customer = new Customer(document); 

    // If this nested loop is removed, the memory doesn't grow 
    foreach(Agency agency in customer.Agencies) 
    { 
      // Gets a writer from a factory for the agency id. 
      IndexWriter writer = WriterFactory.Instance.GetWriter(agency.Id); 

      // Builds an agency-specific document from the customer 
      Document customerDocument = customer.GetAgencyDocument(agency.Id); 

      // Adds the document to the agency's lucene index 
      writer.AddDocument(customerDocument); 
    } 
} 

EDIT:ソリューション

問題は、私は内側のループで「文書」オブジェクトのインスタンスを再利用していなかったし、その

は私のプロセスは、このようになります私のサービスのメモリ使用量が激しくなってしまった。ドキュメントの1つのインスタンスを再利用するだけで、私の問題は解決しました。

ありがとうございました。

+3

は、それ自体で、このコードは、漏洩ではありません。 –

+4

「メモリを大量に使用する」と「メモリリークを行う」の違いがあります。 – David

+2

あなたはそれをあまりにも単純化しました。 –

答えて

2

まず、メモリ使用量を最小限に抑えてガベージコレクタの負担を軽減するために、とFieldのインスタンスをIndexWriter.AddDocument()に再利用する必要があります。

•再利用文書とフィールドのインスタンスを使用すると、フィールドの値を変更できるようにする新しい のsetValue(...)メソッドがあるのLucene 2.3の通り。 これにより、多くの追加された ドキュメントで1つのFieldインスタンスを再利用できるため、GCコストを大幅に節約できます。 単一のDocumentインスタンスを作成し、複数のFieldインスタンスを追加するのが最善ですが、 はこれらのFieldインスタンスを保持し、追加されたドキュメントごとに の値を変更して再利用します。たとえば、あなたはidField、 bodyField、nameField、storedField1などがあるかもしれません。文書が追加された後、 フィールド値(idField.setValue(...)、 など)を直接変更してから、 Documentインスタンス。

のドキュメント内で1つのFieldインスタンスを再利用することはできません。そのフィールドを含む文書 がインデックスに追加されるまで、フィールドの値を変更しないでください。それは本当にあなたが何をしているかに依存

http://wiki.apache.org/lucene-java/ImproveIndexingSpeed

2

キーは、customerscustomer.Agenciesの初期化の仕方に関係します。できる場合は、Listのタイプを返すのではなく、返品タイプIEnumerable<Customer>IEnumerable<Agency>としてください。これにより、メモリの消費量は少なくて済みますが、処理に時間がかかることがあります。

コードをバッチで実行することもできます。そのため、上記のコードを使用してください。List<Customer> customersは、一度に10,000個のバッチで埋め込みます。

+0

ありがとう、私はこれを試してみます。 – dandel

+0

私は400000の顧客とIEnumerableに行きません –

+0

@memetolsen私はデータソースに依存していると思います - SQLでは間違いなく問題になる可能性があります。 – RedFilter

1

を、あなたはリストが使用しているメモリの量を変更しないでください。

これは、リスト内のメモリ使用の原因となっている項目に何かしている必要があります。

あなたは、あなたが達成しようとしていることを見て、同時にメモリ内のすべてのデータを持たないようにプログラムを再設計する必要があります。

1

メモリの使用量を減らしたい場合は、基本的な解答は分割することです。

1つの代理店のすべての顧客をCustomersForAgencyコレクションに入れて、それを処理します。

CustomersForAgencyコレクションが有効範囲外になった場合、そのすべての顧客と(オプションで代理店)が範囲外になり、.netがメモリを再利用できるようになります。

もちろん、メモリ割り当ての大部分は顧客用であり、処理に使用される他の永続インスタンスではないと仮定しています。私はここで起こっされると信じて何

+0

これは私が以前に試したことですが、顧客は代理店以上に存在することがあります。つまり、代理店を繰り返し処理すると、顧客はデータソースから各代理店ごとに一度問い合わせを受けることになります。 – dandel

+0

それは仕事を壊す一つの方法でした。現時点ではブルートフォースアプローチを採用していますが、最適化には要件と実装の深い知識が必要です。それはあなたです。あなたが知っているものから始まり、それを攻撃したり、何が起こったかを見たり、横向きの思考が狡猾な計画につながります。後者は可能かもしれませんが、このコードを読んでいる場合は、「寝る」必要があります。何か別のことをしてください。しばしば狡猾な計画はそれについてあまりにも難しく考えないことから生まれます。 –

4

は次のとおりです。

あなたは、ループ内のあまりのオブジェクトの作成を持っています。可能であれば、ループ内でnew()キーワードを使用しないでください。ループ全体で再利用可能なオブジェクトを初期化し、作業のためにデータを渡します。ガベージコレクションは深刻な問題になり、ガベージコレクタがあなたに追いつくことができず、収集を延期するため、その多くのループ内に新しいオブジェクトを構築しないでください。

これが真である場合はまず試してみてください.Xループごとにガベージコレクションを強制して、ファイナライザが終了するのを待ってください。これによりメモリがダウンした場合、これが問題であることがわかります。それを解決するのは簡単です。ループの繰り返しごとに新しいインスタンスを作成しないでください。

+0

ありがとうございました!それが問題でした。私はそれを解決することができると信じて:) – dandel

関連する問題