주 스레드는 GUI 스레드이고 다른 스레드는 작업자입니다.
앱에는 일부 컨트롤이있는 WPF 양식이 하나 있습니다. 디렉토리를 선택할 수있는 버튼이 있습니다. 디렉토리를 선택한 후 응용 프로그램은 해당 디렉토리에서 .jpg 파일을 검색하고 축소판이 해시 테이블에 있는지 확인합니다. 그들이 있다면, 그것은 아무것도하지 않습니다. 그렇지 않으면 작업자의 전체 파일 이름을 대기열에 추가합니다.
Worker는이 대기열에서 WPF의 JpegBitmapDecoder 및 BitmapFrame을 사용하여 JPEG 이미지를로드하고 (WPF의 TransformedBitmap을 사용하여) 축소판을 만들고 해시 테이블에 추가하여 파일 이름을 가져옵니다.
큰 이미지 (예 : 5000x5000 픽셀)의 축소판을 만들 때이 응용 프로그램의 메모리 사용을 제외한 모든 기능이 정상적으로 작동합니다. 내 양식에 메모리 사용량 (GC.GetTotalMemory() 및 Process.GetCurrentProcess(). PrivateMemorySize64)을 표시하기 위해 텍스트 상자를 추가했으며 매우 놀랐습니다. cuz GC.GetTotalMemory()는 1 - 2MB에 가깝고 개인 메모리 크기 지속적으로, 특히 새로운 이미지를로드 할 때 증가합니다 (이미지 당 ~ 100MB).
모든 이미지를로드하고 이미지 축소판을 만들고 원본 이미지를 비운 후에도 개인 메모리 크기는 ~ 700-800Mbyte에 머물러 있습니다. 내 VirtualBox는 512MB의 실제 메모리로 제한되며 VirtualBox의 Windows는이 거대한 메모리 소비를 처리하기 위해 많은 양을 스왑하기 시작합니다. 내가 뭔가 잘못하고있는 것 같아요,하지만이 문제를 조사하는 방법, GC에 따라 사촌, 할당 된 메모리 크기가 매우 낮습니다.GC.GetTotalMemory()가 너무 낮을 때 C# WPF 응용 프로그램이 너무 많은 메모리를 사용합니다.
썸네일 로더 클래스의 코드를 첨부 : 나는 영상과 관련이있다 생각
class ThumbnailLoader
{
Hashtable thumbnails;
Queue<string> taskqueue;
EventWaitHandle wh;
Thread[] workers;
bool stop;
object locker;
int width, height, processed, added;
public ThumbnailLoader()
{
int workercount,i;
wh = new AutoResetEvent(false);
thumbnails = new Hashtable();
taskqueue = new Queue<string>();
stop = false;
locker = new object();
width = height = 64;
processed = added = 0;
workercount = Environment.ProcessorCount;
workers=new Thread[workercount];
for (i = 0; i < workercount; i++) {
workers[i] = new Thread(Worker);
workers[i].IsBackground = true;
workers[i].Priority = ThreadPriority.Highest;
workers[i].Start();
}
}
public void SetThumbnailSize(int twidth, int theight)
{
width = twidth;
height = theight;
if (thumbnails.Count!=0) AddTask("#resethash");
}
public void GetProgress(out int Added, out int Processed)
{
Added = added;
Processed = processed;
}
private void AddTask(string filename)
{
lock(locker) {
taskqueue.Enqueue(filename);
wh.Set();
added++;
}
}
private string NextTask()
{
lock(locker) {
if (taskqueue.Count == 0) return null;
else {
processed++;
return taskqueue.Dequeue();
}
}
}
public static string FileNameToHash(string s)
{
return FormsAuthentication.HashPasswordForStoringInConfigFile(s, "MD5");
}
public bool GetThumbnail(string filename,out BitmapFrame thumbnail)
{
string hash;
hash = FileNameToHash(filename);
if (thumbnails.ContainsKey(hash)) {
thumbnail=(BitmapFrame)thumbnails[hash];
return true;
}
AddTask(filename);
thumbnail = null;
return false;
}
private BitmapFrame LoadThumbnail(string filename)
{
FileStream fs;
JpegBitmapDecoder bd;
BitmapFrame oldbf, bf;
TransformedBitmap tb;
double scale, dx, dy;
fs = new FileStream(filename, FileMode.Open);
bd = new JpegBitmapDecoder(fs, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
oldbf = bd.Frames[0];
dx = (double)oldbf.Width/width;
dy = (double)oldbf.Height/height;
if (dx > dy) scale = 1/dx;
else scale = 1/dy;
tb = new TransformedBitmap(oldbf, new ScaleTransform(scale, scale));
bf = BitmapFrame.Create(tb);
fs.Close();
oldbf = null;
bd = null;
GC.Collect();
return bf;
}
public void Dispose()
{
lock(locker) {
stop = true;
}
AddTask(null);
foreach (Thread worker in workers) {
worker.Join();
}
wh.Close();
}
private void Worker()
{
string curtask,hash;
while (!stop) {
curtask = NextTask();
if (curtask == null) wh.WaitOne();
else {
if (curtask == "#resethash") thumbnails.Clear();
else {
hash = FileNameToHash(curtask);
try {
thumbnails[hash] = LoadThumbnail(curtask);
}
catch {
thumbnails[hash] = null;
}
}
}
}
}
}
큰 개체 힙이있는 것과 같은 소리가납니다 ... 이미지 처리 과정에서 시간이 지남에 따라 성능 카운터를 얻을 수 있습니까? LOH는 표준 메모리와 같은 방식으로 수집하지 않으며 (정확하게 기억한다면) 조각화에 훨씬 더 민감합니다 ... – LorenVS
이것은 관리되지 않는 메모리에 대해 여러 가지 알려진 문제점이있는 WPF의 버그 일 수 있습니다. Connect (http://connect.microsoft.com/)에서이 사실을 알려주기를 권합니다. 메모리 누수가 응용 프로그램에 문제가 발생하여 수정 사항을 얻을 수없는 경우 코드의 중요 부분을 다른 프로세스 나 AppDomain으로 옮길 수 있습니다. –