파일 (약 100 MB)에서 많은 주식 데이터 기록을로드하는 Stock
클래스가 있습니다. 나는 두 개의 Stock
오브젝트를 취하고이 둘 사이의 통계적 관계를 계산 한 후 파일에 결과를 쓰는 Pair
클래스를 가지고 있습니다.감지 할 수없는 메모리 누수
내 주요 방법에는 주식 쌍 (약 500) 목록을 통과하는 루프가 있습니다. 두 개의 주식 오브젝트를 생성 한 다음 두 개의 주식 오브젝트를 생성합니다. 이 시점에서 쌍 계산은 파일에 쓰여지고 객체로 끝납니다. 다음 계산으로 계속 진행할 수 있도록 메모리를 확보해야합니다.
내가 루프의 끝에 다음 두 줄을 추가 한 null로 3 개체를 설정하는 나는 또한:
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
이 끝난 스테핑이 두 줄을 논제 단지 중 단지 무료 50 MB의 것 루프 반복마다 할당되는 200-300MB (작업 관리자에서 표시).
시스템에 메모리 부족 예외가 발생하기 전에 약 8 ~ 10 쌍의 프로그램이 수행됩니다. 메모리 사용량은 약 1.5GB에서 충돌 할 때까지 꾸준히 증가합니다. (이것은 Win7 Ultimate를 실행하는 8 기가 바이트 기계입니다)
가비지 수집에 대한 많은 경험이 없습니다. 내가 뭔가 잘못하고 있는거야?
다음은 내 코드입니다. (참고 : 프로그램에는 두 가지 모드가 있습니다 .1> 시스템에 새 쌍이 추가되는 모드 2>filesystemwatcher
이벤트에 따라 실시간으로 쌍 파일을 업데이트하는 일반 모드입니다.) 주식 데이터 QCollector라는 외부 응용 프로그램에 의해 업데이트됩니다)이 추가 모드에서 실행 MainForm
의 세그먼트
:.
foreach (string line in PairList)
{
string[] tokens = line.Split(',');
stockA = new Stock(QCollectorPath, tokens[0].ToUpper());
stockB = new Stock(QCollectorPath, tokens[1].ToUpper());
double ratio = double.Parse(tokens[2]);
Pair p = new Pair(QCollectorPath, stockA, stockB, ratio);
// at this point the pair is written to file (constructor handles this)
// commenting out the following lines of code since they don't fix the problem
// stockA = null;
// stockB = null;
// p = null;
// refraining from forced collection since that's not the problem
// GC.Collect(GC.MaxGeneration);
// GC.WaitForPendingFinalizers();
// so far this is the only way i can fix the problem by setting the pair classes
// references to StockA and StockB to null
p.Kill();
}
내가 요청에 따라 더 많은 코드를 추가하고 : Stock
및 Pair
TimeSeries
의 서브 클래스는이, 어떤 공통 기능을 가지고있다. ity
public abstract class TimeSeries {
protected List<string> data;
// following create class must be implemented by subclasses (stock, pair, etc...)
// as each class is created differently, although their data formatting is identical
protected void List<string> Create();
// . . .
public void LoadFromFile()
{
data = new List<string>();
List<StreamReader> srs = GetAllFiles();
foreach (StreamReader sr in srs)
{
List<string> temp = new List<string>();
temp = TurnFileIntoListString(sr);
data = new List<string>(temp.Concat(data));
sr.Close()
}
}
// uses directory naming scheme (according to data month/year) to find files of a symbol
protected List<StreamReader> GetAllFiles()...
public static List<string> TurnFileIntoListString(StreamReader sr)
{
List<string> list = new List<string>();
string line;
while ((line = sr.ReadLine()) != null)
list.Add(line);
return list;
}
// this is the only mean to access a TimeSeries object's data
// this is to prevent deadlocks by time consuming methods such as pair's Create
public string[] GetListCopy()
{
lock (data)
{
string[] listCopy = new string[data.count];
data.CopyTo(listCopy);
return listCopy();
}
}
}
public class Stock : TimeSeries
{
public Stock(string dataFilePath, string symbol, FileSystemWatcher fsw = null)
{
DataFilePath = dataFilePath;
Name = symbol.ToUpper();
LoadFromFile();
// to update stock data when external app updates the files
if (fsw != null) fsw.Changed += FileSystemEventHandler(fsw_Changed);
}
protected void List<string> Create()
{
// stock files created by external application
}
// . . .
}
public class Pair : TimeSeries {
public Pair(string dataFilePath, Stock stockA, Stock stockB, double ratio)
{
// assign parameters to local members
// ...
if (FileExists())
LoadFromFile();
else
Create();
}
protected override List<string> Create()
{
// since stock can get updated by fileSystemWatcher's event handler
// a copy is obtained from the stock object's data
string[] listA = StockA.GetListCopy();
string[] listB = StockB.GetListCopy();
List<string> listP = new List<string>();
int i, j;
i = GetFirstValidBar(listA);
j = GetFirstValidBar(listB);
DateTime dtA, dtB;
dtA = GetDateTime(listA[i]);
dtB = GetDateTime(listB[j]);
// this hidden segment adjusts i and j until they are starting at same datetime
// since stocks can have different amount of data
while (i < listA.Count() && j < listB.Count)
{
double priceA = GetPrice(listA[i]);
double priceB = GetPrice(listB[j]);
double priceP = priceA * ratio - priceB;
listP.Add(String.Format("{0},{1:0.00},{2:0.00},{3:0.00}"
, dtA
, priceP
, priceA
, priceB
);
if (i < j)
i++;
else if (j < i)
j++;
else
{
i++;
j++;
}
}
}
public void Kill()
{
data = null;
stockA = null;
stockB = null;
}
}
필자는 fsw를 null로 설정했습니다. 추가 작업이 필요하지 않았기 때문에 kill 메소드가 트릭을 수행하고 있다고 생각했습니다. 모든 도움을 주셔서 다시 한 번 감사드립니다. – bkarj