2017-11-15 13 views
0

메모리를 계속 먹기 때문에 몇 달에 한 번씩 수동으로 다시 시작해야하는 기존 Windows 서비스 (C#으로 작성 됨)를 디버깅합니다.NHibernate가있는 Windows 서비스가 사용 메모리를 늘리고 있습니다.

서비스는 그리 복잡하지 않습니다. 제품을 보유하고있는 외부 서버에서 json 파일을 요청합니다. 다음으로이 json 파일을 제품 목록으로 구문 분석합니다. 이러한 각 제품에 대해이 제품이 이미 데이터베이스에 있는지 확인하고 있습니다. 만약 존재하지 않는다면 속성이 업데이트 될 것입니다.

데이터베이스는 PostgreSQL 데이터베이스이며 우리는 ORM으로 NHibernate v3.2.0을 사용합니다. DotMemory overvies

서비스가 시작하고 30 대 이후는 일을 시작 :

나는 실행시 서비스를 프로파일 JetBrains의 DotMemory을 사용하고있다. SnapShot # 1은 첫 번째 실행 전에 만들어집니다. 스냅 샷 # 6은 5 회에 걸쳐 실행되었습니다. 다른 스냅 샷은 실행 후에도 생성됩니다. 각 실행 후에 볼 수 있듯이 개체 수가 약 증가함에 따라 증가합니다. 60k이고 사용 된 메모리는 매 실행 후 수 MB로 증가합니다.

try 
{ 
    // Trying to fix certificate errors: 
    ServicePointManager.ServerCertificateValidationCallback += delegate 
    { 
     _logger.Debug("Cert validation work around"); 
     return true; 
    }; 

    _timer = new Timer(_interval) 
    { 
     AutoReset = false // makes it fire only once, restart when work is done to prevent multiple runs 
    }; 
    _timer.Elapsed += DoServiceWork; 
    _timer.Start(); 
} 
catch (Exception ex) 
{ 
    _logger.Error("Exception in OnStart: " + ex.Message, ex); 
} 

그리고 내 DoServiceWork :

Snapshot #6

가 여기 내 ONSTART 코드입니다 :

가까이 스냅 샷 # 6에서 찾고

의 유지 크기가 대부분 NHibernate에 세션 객체에 의해 사용되는 표시

try 
{ 
    // Call execute 
    var processor = new SAPProductProcessor(); 
    processor.Execute(); 
} 
catch (Exception ex) 
{ 
    _logger.Error("Error in DoServiceWork", ex); 
} 
finally 
{ 
    // Next round: 
    _timer.Start(); 
} 

SAPProductProcessor에서 2 회의 db 호출. 둘 다 루프에 있습니다. 제품이 테이블에 이미있는 경우 JSON 파일에서 모든 제품을 통해 I 루프와 제품 코드를 사용하여 확인 :

ProductDto dto; 
using (var session = SessionFactory.OpenSession()) 
{ 
    using (var transaction = session.BeginTransaction(IsolationLevel.ReadCommitted)) 
    { 
     var criteria = session.CreateCriteria<ProductDto>(); 
     criteria.Add(Restrictions.Eq("Code", code)); 
     dto = criteria.UniqueResult<ProductDto>(); 
     transaction.Commit(); 
    } 
} 
return dto; 

그리고를 productDto 내가 사용하는 저장 업데이트 될 때 :

using (var session = SessionFactory.OpenSession()) 
{ 
    using (var transaction = session.BeginTransaction(IsolationLevel.ReadCommitted)) 
    { 
     session.SaveOrUpdate(item); 
     transaction.Commit(); 
    } 
} 

메모리와 객체의 수를 늘리지 않으려면 위의 코드를 어떻게 변경해야할지 모르겠습니다.

이미 using (var session = SessionFactory.OpenSession()) 대신 var session = SessionFactory.GetCurrentSession();을 사용했지만 메모리 증가를 막지 못했습니다. 내 데이터 액세스 클래스 MultiSessionFactoryProvider sessionFactoryProvider의 생성자에서

업데이트가 주입된다. 그리고 기본 클래스는 : base(sessionFactoryProvider.GetFactory("data"))으로 호출됩니다. 그때 끝에서 시작시 base.BeginSessionbase.EndSession를 호출 내 데이터 액세스 클래스에서

ISession session = ThreadLocalSessionContext.Unbind(_sessionFactory); 
if (session != null) 
{ 
    session.Close(); 
} 

:

ISession session = _sessionFactory.GetCurrentSession(); 
if (session == null) 
{ 
    session = _sessionFactory.OpenSession(); 
    ThreadLocalSessionContext.Bind(session); 
} 

그리고 EndSession이 기본 클래스는 방법 BeginSession 있습니다.

+0

은 'DoServiceWork'싱글 톤입니까? 나는 SAPProductProcessor가 매번 생성된다는 것을 알았다. 아마도 그것은 보는 무엇입니까? –

+2

SessionFactory는 속성입니까? SessionFactory는 어디에 생성됩니까? 프로세스 (또는 AppDomain)에 한 번만 만들어야합니다. –

+0

비교를 열고 모든 새 개체를 열고 어떤 개체가 보관되어 있고 왜 있는지 확인합니다. –

답변

0

싱글 톤에 대한 제안을 통해 데이터 액세스 클래스를 자세히 살펴 보았습니다.

모든 실행과 함께이 클래스를 만들 때 NHibernate 메모리가 범위를 벗어날 때 해제 될 것이라고 생각했습니다. 클래스의 소멸자에서 일부 처리 호출을 추가했습니다. 하지만 그건 제대로 작동하지 않을 수도 있고, 그렇지 않을 수도 있습니다. 이제 데이터 액세스 클래스를 정적 ​​필드에 저장하고 다시 사용합니다. 이제는 내 기억이 더 이상 증가하지 않고 열려있는 물건의 수는 똑같이 유지됩니다. 난 단지 DotMemory를 사용하여 다시 한 번 이상 150 번 실행하고 마지막 스냅 샷의 메모리는 약 105MB이고 객체의 수는 여전히 117k이고 내 SessionFactory 사전은 150MB * 4MB 대신 4MB입니다. .