2012-04-16 5 views
4

중첩 for 루프로 내 응용 프로그램에 메모리 문제가있어 개선 방법을 찾을 수 없습니다. 나는 linq를 사용하여 시도했지만 내부적으로 메모리 누수가 있기 때문에 동일하다고 생각한다.중첩 루프 최적화

편집 : 내가 요청한대로, 나는 나의 문제에 관하여 더 많은 정보를 제공 할 것이다.

Lucene 문서 저장소에 색인 된 모든 고객 (약 400.000)이 있습니다. 각 고객은 2 개 이상의 대행사에 출석 할 수 있으며 그 중 일부는 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); 
    } 
} 

편집 : 솔루션

문제는 내가 내부 루프에서 "문서"개체의 인스턴스를 재사용하지 않은, 그리고 그

내 프로세스는 다음과 같습니다 내 서비스의 메모리 사용량이 지나치게 증가했습니다. 전체 프로세스에 대해 Document의 단일 인스턴스를 재사용하면 문제가 해결됩니다.

모두에게 감사드립니다.

+3

은, 그 자체로이 코드를 누설하지 않습니다. –

+4

"많은 메모리 사용"과 "메모리 누수"사이에는 차이가 있습니다. – David

+2

너무 단순화했습니다. –

답변

2

우선 메모리 사용량을 최소화하고 가비지 수집기에 대한 부담을 덜어주기 위해및 Field 인스턴스를 IndexWriter.AddDocument()으로 다시 사용해야합니다. 루씬 2.3로 재사용 문서 및 필드 인스턴스 •

는 필드의 값을 변경할 수 있도록 새로운 의 setValue (...) 방법이있다. 이렇게하면 많은 추가 된 문서에서 단일 Field 인스턴스를 재사용 할 수 있으므로 상당한 GC 비용을 절약 할 수 있습니다. 단일 문서 인스턴스를 만든 다음 여러 개의 Field 인스턴스를 추가하는 것이 가장 좋지만 필드 인스턴스를 보유하고 추가 된 각 문서의 값을 변경하여 다시 사용합니다. 예를 들어, idField, bodyField, nameField, storedField1 등이있을 수 있습니다. 문서가 추가 된 후 필드 값 (idField.setValue (...), 등)을 직접 변경 한 다음 다시 추가하십시오 Document 인스턴스.

문서 내에서 단일 필드 인스턴스 인 을 다시 사용할 수없고 해당 필드가 포함 된 문서가 색인에 추가 될 때까지 필드 값을 변경해서는 안됩니다. 정말 당신이 무엇을하고 있는지에 따라 달라집니다

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

메모리 사용량을 줄이려면 기본 대답은 해체하는 것입니다.

그래서 한 대행사의 모든 고객을 CustomersForAgency 컬렉션으로 가져 와서 바로 처리하십시오.

CustomersForAgency 컬렉션이 범위를 벗어나거나 지우면 모든 고객과 (선택 사항으로 해당 대행사) 범위를 벗어나 .net에서 메모리를 다시 사용할 수 있습니다.

물론 메모리 할당의 대부분이 고객을위한 것이며 처리를 위해 사용되는 다른 영구 인스턴스가 아니라고 가정합니다.

+0

이전에 시도했지만 고객이 대행사 이상에있을 수 있습니다. 즉, 대행사를 반복하면 고객이 모든 대행사에 대해 데이터 소스에서 한 번 조회됩니다. – dandel

+0

그것은 그 일을 깨는 한 가지 방법이었습니다. 현재 무차별 대입 방식을 사용하고 있으며, 최적화를 위해서는 요구 사항과 구현에 대한 깊은 지식이 필요합니다. 너야. 두 가지 방법은 당신이 아는 것부터 시작해서, 공격하거나, 어떤 일이 일어나는지, 또는 측 면적 사고는 교활한 계획으로이 끕니다. 후자가 가능할 수도 있지만,이 코드를 사용하여 생활한다면 "잠자코"해야하며, 조금만 다른 것을하십시오. 종종 교활한 계획은 그것에 대해 너무 열심히 생각하지 않기 때문에 발생합니다. –

4

은 내가 여기에 일어나고 생각하는 것은 :

당신은 루프 내부에 너무 많은 객체 생성이있다. 가능하다면 루프 내에서 new() 키워드를 사용하지 마십시오. 루프에서 재사용 가능한 객체를 초기화하고 작업 할 데이터를 전달하십시오. 가비지 수집이 심각한 문제가되고 가비지 컬렉터가 수집을 지연하여 수집을 지연시킬 수 있으므로 많은 루프 내에 새로운 객체를 생성하지 마십시오.

이것이 사실이라면 시도해 볼 수있는 첫 번째 일은 모든 X 루프 가비지 콜렉션을 강제 실행하고 대기중인 finalizer를 기다리는 것입니다. 이렇게하면 메모리가 줄어들어 이것이 문제라는 것을 알 수 있습니다. 루프 반복마다 새 인스턴스를 만들지 않아도됩니다.

+0

감사합니다 !!! 그것이 문제였습니다. 나는 그것을 해결할 수있을 것이라고 믿는다. :) – dandel