【发布时间】:2014-10-04 00:57:52
【问题描述】:
我有一个例程扫描文件夹中的图像,然后为每个图像,将其转换为缩略图,然后将该缩略图上传到数据库。仅当数据库中该特定文件夹没有任何项目时,它才会运行。我的问题是我在处理几个文件夹后收到内存不足异常,我不确定泄漏发生在哪里。我已经尝试在循环中处理所有我可以丢弃的东西,但显然有些东西仍然从裂缝中掉下来。
private bool LoadImages(int folderid, int parentid) {
ProgressScreen tfrm = new ProgressScreen();
tfrm.Hide();
DataTable mtable = new DataTable();
List<FileInfo> lfile;
mtable = Requests.ProcessSQLCommand(sqlconn, "Select f.ID, f.FolderName,f.FolderPath,f.ParentID,f.Root from Folders f where f.ID = " + folderid);
DataTable ptable = Requests.ProcessSQLCommand(sqlconn, "Select Root from Folders where ID = " + parentid);
if (ptable != null && ptable.Rows.Count > 0) {
if (ptable.Rows[0]["Root"].ToString().ToLower() == "true") {
return false;
}
}
bool process = true;
DirectoryInfo di = new DirectoryInfo(mtable.Rows[0]["FolderPath"].ToString());
FileInfo[] smFiles = di.GetFiles("*.jpg", SearchOption.TopDirectoryOnly);
lfile = smFiles.ToList<FileInfo>();
if (lfile.Count <= 0) {
process = false;
}
if (process) {
tfrm.Show(this);
for (int c = 0; c < lfile.Count; c++) {
if (((FileInfo)lfile[c]).Extension == ".txt") {
lfile.RemoveAt(c);
}
if (((FileInfo)lfile[c]).FullName.ToLower().Contains("cover")) {
lfile.RemoveAt(c);
}
}
for (int b = 0; b < lfile.Count; b++) {
Cursor.Current = Cursors.WaitCursor;
this.Enabled = false;
try {
tfrm.Location = new Point((Screen.PrimaryScreen.WorkingArea.Width / 2) - (tfrm.Width / 2), (Screen.PrimaryScreen.WorkingArea.Height / 2) - (tfrm.Height / 2));
} catch {
}
tfrm.SetProgress((int)(((double)(b + 1) / (double)lfile.Count) * 100), "Loading Images", lfile[b].Name.ToString());
tfrm.Refresh();
int recid = 0;
DataTable ttable = Requests.ProcessSQLCommand(sqlconn, "Insert into Image (Name,FolderID,ParentID) VALUES ('" + lfile[b].Name + "'," + folderid + "," + parentid + ") Select SCOPE_IDENTITY()");
if (ttable != null && ttable.Rows.Count > 0) {
recid = int.Parse(ttable.Rows[0][0].ToString());
}
if (recid > 0) {
Image timg = null;
byte[] traw = new byte[0];
traw = File.ReadAllBytes(lfile[b].FullName);
MemoryStream tstream = new MemoryStream(traw);
timg = System.Drawing.Image.FromStream(tstream);
tstream.Dispose();
timg = Requests.FixedSize(timg, 600, 600);
tstream = new MemoryStream();
timg.Save(tstream, System.Drawing.Imaging.ImageFormat.Png);
timg.Dispose();
traw = new byte[0];
traw = tstream.ToArray();
tstream.Dispose();
System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(sqlconn);
con.Open();
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("Update Image set [Thumb] = Convert(VarBinary(MAX),@Image) where ID = " + recid, con);
cmd.Parameters.AddWithValue("@Image", traw);
cmd.ExecuteNonQuery();
con.Dispose();
}
}
this.Enabled = true;
Cursor.Current = Cursors.Default;
tfrm.Close();
tfrm.Dispose();
System.Windows.Forms.Application.UseWaitCursor = false;
return true;
} else {
return false;
}
}
固定尺寸法:
public static Image FixedSize(Image imgPhoto, int Width, int Height) {
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)Width / (float)sourceWidth);
nPercentH = ((float)Height / (float)sourceHeight);
if (nPercentH < nPercentW) {
nPercent = nPercentH;
destX = System.Convert.ToInt16((Width - (sourceWidth * nPercent)) / 2);
} else {
nPercent = nPercentW;
destY = System.Convert.ToInt16((Height - (sourceHeight * nPercent)) / 2);
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.Magenta);
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto, new Rectangle(destX, destY, destWidth, destHeight), new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
原始图像(固定大小之前)的范围从 2MB 到 20MB,表中返回的图像 (max(len(image)) 约为 750 KB。(编辑:更正的文件大小)
每个文件夹的图像数量 ~100-150
我已经查看和调试过,但找不到导致 OOM 问题的原因,有人可以指出错误,或者为我正在做的事情提供更好的优化吗?
【问题讨论】:
-
你可能不是内存不足,而是资源不足。那里有很多东西应该被处理,但可能不会。你可以通过任务管理器查看 GDI 对象和句柄。
-
FWIW,使用the
usingstatement 将大大清理代码 -
您拥有的最大图像的尺寸是多少?您是否以 32 位运行此代码?它总是在特定图像上爆炸吗?
-
正如@VikasGupta 指出的那样,由于未压缩图像的大小,100MB JPG 几乎肯定会导致 OOM(甚至可能在 x64 上)。
-
@VikasGupta 最大图像为 18.3MB 3744x6516x24b 程序编译为 64 位。不,它不是一个特定的图像,通常是在处理大约 20 到 30 个文件夹之后。
标签: c# image memory-leaks bytearray