asp.net程序里增加了这段代码后,服务器内存不断增加,直至程序池内存超限回收!我不太懂程序,查了很久也不见效,请高手指教(替换前后的全部程序代码在这里):WebBrowser m_WebBrowser = null;
private void _GenerateHtmlToImgImage()
{
m_WebBrowser = new WebBrowser();
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Enabled = false;
t.Interval = 10000;
t.Tick += t_Tick;
m_WebBrowser.ScrollBarsEnabled = false;
t.Enabled = true;
m_WebBrowser.Navigate(m_Url);
m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
while (m_WebBrowser != null && m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
if (m_WebBrowser != null)
m_WebBrowser.Dispose();
m_WebBrowser = null;
}
void t_Tick(object sender, EventArgs e)
{
((System.Windows.Forms.Timer)sender).Stop();
WebBrowser tmp = m_WebBrowser;
if (tmp != null)
{
m_WebBrowser = null;
if (tmp.ReadyState != WebBrowserReadyState.Complete)
{
tmp.Stop();
tmp.Dispose();
}
}
private void _GenerateHtmlToImgImage()
{
m_WebBrowser = new WebBrowser();
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Enabled = false;
t.Interval = 10000;
t.Tick += t_Tick;
m_WebBrowser.ScrollBarsEnabled = false;
t.Enabled = true;
m_WebBrowser.Navigate(m_Url);
m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
while (m_WebBrowser != null && m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
if (m_WebBrowser != null)
m_WebBrowser.Dispose();
m_WebBrowser = null;
}
void t_Tick(object sender, EventArgs e)
{
((System.Windows.Forms.Timer)sender).Stop();
WebBrowser tmp = m_WebBrowser;
if (tmp != null)
{
m_WebBrowser = null;
if (tmp.ReadyState != WebBrowserReadyState.Complete)
{
tmp.Stop();
tmp.Dispose();
}
}
这个代码之前没有内存泄露,就是增加了这个时间限制之后才出现的内存问题,所以我才下大力寻找的!能否拜托版主帮我仔细看看?这是修改前的代码,只修改了这部分,其余没动(修改前的全部程序代码在这里): private void _GenerateHtmlToImgImage()
{
WebBrowser m_WebBrowser = new WebBrowser();
m_WebBrowser.ScrollBarsEnabled = false;
m_WebBrowser.Navigate(m_Url);
m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
while (m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
m_WebBrowser.Dispose();
}
private void _GenerateHtmlToImgImage()
{
m_WebBrowser = new WebBrowser();
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Enabled = false;
t.Interval = 10000;
t.Tick += t_Tick;
m_WebBrowser.ScrollBarsEnabled = false;
t.Enabled = true;
m_WebBrowser.Navigate(m_Url);
m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
while (m_WebBrowser != null && m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
if (m_WebBrowser != null)
m_WebBrowser.Dispose();
m_WebBrowser = null;
}
void t_Tick(object sender, EventArgs e)
{
((System.Windows.Forms.Timer)sender).Stop();
WebBrowser tmp = m_WebBrowser;
if (tmp != null)
{
m_WebBrowser = null;
if (tmp.ReadyState != WebBrowserReadyState.Complete)
{
tmp.Stop();
tmp.Dispose();
}
}
不过这段代码看着不舒服:
WebBrowser tmp = m_WebBrowser;
if (tmp != null)
{
m_WebBrowser = null;
if (tmp.ReadyState != WebBrowserReadyState.Complete)
{
tmp.Stop();
tmp.Dispose();
}
}
改一下: if (m_WebBrowser != null)
{
if (m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
{
m_WebBrowser.Stop();
}
m_WebBrowser.Dispose();
m_WebBrowser = null;
}
另外,你说的全局变量是哪个?t?还是别的什么?
还有,System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
改成System.Threading.Timer t = new System.Threading.Timer();不知对不对,改了之后页面卡死,就又改回来了。
基础很差,望高手不吝赐教。
又在codeplex,上看了一个。效果也差不多,你试试看,如果这效率好些就用这个吧。
http://webshooter.codeplex.com/
下面引用MSDN原话:
因此你后面的while循环很可能会导致了无限循环,资源不释放。正确的做法是使用System.Threading.Timer 类。
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();目前在用,改成System.Threading.Timer t = new System.Threading.Timer();反倒不能用了,是不是要在页面最顶端加上这一行才可以:System.Threading.Timer
而事实上,使用了定时器以后,你的那个while部分语句就可以不需要了,这也是sp1234所说的情况,你那段sp1234后面的代码完全是画社添足,应该全部放在定时器中处理。那个定时器内部就做过判断,是超时还是正常结束了,后续逻辑直接跟在后面即可。
我的所有代码都在,可以帮我改改吗?现成的代码我也看不大懂,只要在此基础上能及时释放资源就行。
先谢谢了!
一、while循环里原先只有Application.DoEvents();,现添加Thread.Sleep(300);让每次循环休息下。
while(...)
{
Thread.Sleep(300);
Application.DoEvents();
}二: private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser m_WebBrowser = (WebBrowser)sender;
m_WebBrowser.ClientSize = new Size(this.m_BrowserWidth, this.m_BrowserHeight);
m_WebBrowser.ScrollBarsEnabled = false;
m_Bitmap = new Bitmap(m_WebBrowser.Bounds.Width, m_WebBrowser.Bounds.Height);
m_WebBrowser.BringToFront();
m_WebBrowser.DrawToBitmap(m_Bitmap, m_WebBrowser.Bounds);
m_Bitmap = (Bitmap)m_Bitmap.GetThumbnailImage(m_ThumbnailWidth, m_ThumbnailHeight, null, IntPtr.Zero);
}
改为: private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser m_WebBrowser = (WebBrowser)sender;
m_WebBrowser.ClientSize = new Size(this.m_BrowserWidth, this.m_BrowserHeight);
m_WebBrowser.ScrollBarsEnabled = false;
var tmp = new Bitmap(m_WebBrowser.Bounds.Width, m_WebBrowser.Bounds.Height);
m_WebBrowser.BringToFront();
m_WebBrowser.DrawToBitmap(tmp , m_WebBrowser.Bounds);
m_Bitmap = (Bitmap)tmp.GetThumbnailImage(m_ThumbnailWidth, m_ThumbnailHeight, null, IntPtr.Zero);
tmp.Dispose();//释放临时图片资源
tmp = null;
}三: protected void Button1_Click(object sender, EventArgs e)
{
Bitmap bmp = HtmlToImg.GetHtmlToImg("http://www.baidu.com/", 800, 600, 800, 600);
MemoryStream stream = new MemoryStream();
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] buff = stream.ToArray();
FileStream fs = new FileStream(Server.MapPath(DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg"), FileMode.Create);
stream.WriteTo(fs);
stream.Close();
fs.Close();
}
改为: protected void Button1_Click(object sender, EventArgs e)
{
using(Bitmap bmp = HtmlToImg.GetHtmlToImg("http://www.baidu.com/", 800, 600, 800, 600))
{
bmp.Save(Server.MapPath(DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
}此二处的Bitmap必须释放,否则就会内存泄漏。最后那个错误提示的返回方法请自选搜索,本人不搞asp.net好久了,具体代码已经忘记。
这是啥子啊asp.net 配WebBrowser,在配Timer??这代码比较奇葩想做爬虫玩快照,也不应该在asp.net里玩,你可以写成winfrom服务
我不大会调试,每个步骤结果如下:
一、增加Thread.Sleep(300);后,程序运行缓慢,长时间等待后出现正在中止线程的错误提示:“异常详细信息: System.Threading.ThreadAbortException: 正在中止线程。”
二、编译器错误信息: CS0246: 找不到类型或命名空间名称“var”(是否缺少 using 指令或程序集引用?)
var tmp = new Bitmap(m_WebBrowser.Bounds.Width, m_WebBrowser.Bounds.Height);
去掉var也出错。
三、在".jpg"后面加括号后通过了。
这个程序原来没有内存泄露(至少我没发现),就是增加了限制时间的条件(整个程序只改了这个方法 _GenerateHtmlToImgImage)之后才有了内存泄露。能否请高手直接看看这两段更改前后的代码找出泄漏原因?
_GenerateHtmlToImgImage方法更改前(没发现整个程序有内存泄漏): private void _GenerateHtmlToImgImage()
{
WebBrowser m_WebBrowser = new WebBrowser();
m_WebBrowser.ScrollBarsEnabled = false;
m_WebBrowser.Navigate(m_Url);
m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
while (m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
m_WebBrowser.Dispose();
}_GenerateHtmlToImgImage方法更改,限制程序时间后(内存泄漏很严重):WebBrowser m_WebBrowser = null;
private void _GenerateHtmlToImgImage()
{
m_WebBrowser = new WebBrowser();
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Enabled = false;
t.Interval = 10000;
t.Tick += t_Tick;
m_WebBrowser.ScrollBarsEnabled = false;
t.Enabled = true;
m_WebBrowser.Navigate(m_Url);
m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
while (m_WebBrowser != null && m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
if (m_WebBrowser != null)
m_WebBrowser.Dispose();
m_WebBrowser = null;
}
void t_Tick(object sender, EventArgs e)
{
((System.Windows.Forms.Timer)sender).Stop();
WebBrowser tmp = m_WebBrowser;
if (tmp != null)
{
m_WebBrowser = null;
if (tmp.ReadyState != WebBrowserReadyState.Complete)
{
tmp.Stop();
tmp.Dispose();
}
}
}我的程序是七拼八凑起来的,肯定存在很多问题!但是目前最紧要的还是修改了_GenerateHtmlToImgImage方法之后造成的内存泄露。恳请高手查看具体是哪条代码出的问题!
按理说,所有操作是在多线程中执行的,那么该线程如果执行结束,肯定是会释放资源的,但由于你的代码是asp.net,不方便调试,你可以将代码执行逻辑(按钮点击)放在WinForm下面测试,而最后写文件部分用固定文件名替代测试,主要测试线程是否能够正常结束。另外Thread.Sleep(300);后不会导致变慢的,这个间隔几乎是感觉不到的,而System.Threading.ThreadAbortException异常是必须手动调用Thread类的Abort方法才会产生,但是你的代码中没看到这部分。
如果实在调试不出原因,就别用System.Windows.Forms.Timer了,这里的超时很容易处理,先改用原来的代码,然后在public Bitmap GenerateHtmlToImgImage()函数中,找到“m_thread.Join();”改为:
bool success = m_thread.Join(15000);//考虑到处理图片也要时间,增加5秒
if(success)
return m_Bitmap;
else
throw new Exception("操作超时");//这里返回的异常,由外部调用者捕获并做其它处理。
if(success)
return m_Bitmap;
else
{
m_thread.Abort();//終止线程
throw new Exception("操作超时");//这里返回的异常,由外部调用者捕获并做其它处理。
}
我把简化后的原始代码再次贴出来(就是主贴那个链接里的),这个程序除了不能超时终止之外,别的没发现异常,后来加了时间代码(主贴那个链接里提问得到的答案)就发现内存泄露了。可不可以请高手直接给我这个代码加上限制时间的代码(比如10秒,超时则终止程序释放资源)。总共3个文件:
Default.aspx<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="保存网页快照" onclick="Button1_Click" />
</div>
</form>
</body>
</html>Default.aspx.csusing System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.IO;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
Bitmap bmp = HtmlToImg.GetHtmlToImg("http://www.baidu.com/", 800, 600, 800, 600);
MemoryStream stream = new MemoryStream();
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] buff = stream.ToArray();
FileStream fs = new FileStream(Server.MapPath(DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg"), FileMode.Create);
stream.WriteTo(fs);
stream.Close();
fs.Close();
}
}HtmlToImage.csusing System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
public class HtmlToImg
{
Bitmap m_Bitmap;
string m_Url;
int m_BrowserWidth, m_BrowserHeight, m_ThumbnailWidth, m_ThumbnailHeight;
public HtmlToImg(string Url, int BrowserWidth, int BrowserHeight, int ThumbnailWidth, int ThumbnailHeight)
{
m_Url = Url;
m_BrowserHeight = BrowserHeight;
m_BrowserWidth = BrowserWidth;
m_ThumbnailWidth = ThumbnailWidth;
m_ThumbnailHeight = ThumbnailHeight;
}
public static Bitmap GetHtmlToImg(string Url, int BrowserWidth, int BrowserHeight, int ThumbnailWidth, int ThumbnailHeight)
{
HtmlToImg thumbnailGenerator = new HtmlToImg(Url, BrowserWidth, BrowserHeight, ThumbnailWidth, ThumbnailHeight);
return thumbnailGenerator.GenerateHtmlToImgImage();
}
public Bitmap GenerateHtmlToImgImage()
{
Thread m_thread = new Thread(new ThreadStart(_GenerateHtmlToImgImage));
m_thread.SetApartmentState(ApartmentState.STA);
m_thread.Start();
m_thread.Join();
return m_Bitmap;
}
private void _GenerateHtmlToImgImage()
{
WebBrowser m_WebBrowser = new WebBrowser();
m_WebBrowser.ScrollBarsEnabled = false;
m_WebBrowser.Navigate(m_Url);
m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
while (m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
m_WebBrowser.Dispose();
}
private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser m_WebBrowser = (WebBrowser)sender;
m_WebBrowser.ClientSize = new Size(this.m_BrowserWidth, this.m_BrowserHeight);
m_WebBrowser.ScrollBarsEnabled = false;
m_Bitmap = new Bitmap(m_WebBrowser.Bounds.Width, m_WebBrowser.Bounds.Height);
m_WebBrowser.BringToFront();
m_WebBrowser.DrawToBitmap(m_Bitmap, m_WebBrowser.Bounds);
m_Bitmap = (Bitmap)m_Bitmap.GetThumbnailImage(m_ThumbnailWidth, m_ThumbnailHeight, null, IntPtr.Zero);
}
}net2.0的运行环境。拜托高手直接帮我在这个完整的程序里增加限制程序运行时间的代码,超时就终止程序释放资源。
{
Thread m_thread = new Thread(new ThreadStart(_GenerateHtmlToImgImage));
m_thread.SetApartmentState(ApartmentState.STA);
m_thread.Start();
bool success = m_thread.Join(15000);//考虑到处理图片也要时间,增加5秒
if(success)
return m_Bitmap;
else
{
m_thread.Abort();//終止线程
throw new Exception("操作超时");//这里返回的异常,由外部调用者捕获并做其它处理。
}
return m_Bitmap;
}
调用:
protected void Button1_Click(object sender, EventArgs e)
{
try
{
using(Bitmap bmp = HtmlToImg.GetHtmlToImg("http://www.baidu.com/", 800, 600, 800, 600))
{
bmp.Save(Server.MapPath(DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
catch(Exception ex)
{
HttpResponse response = HttpContext.Current.Response;
response.Write(ex.Message);
response.Close();
}
}
备注,最后3行代码未测试,凭感觉写的。
{
/// <summary>
/// 地址
/// </summary>
private string _url = "about:blank";
/// <summary>
/// 宽
/// </summary>
private int _width = 800;
/// <summary>
/// 高
/// </summary>
private int _height = 600;
/// <summary>
/// 缩略图宽
/// </summary>
private int _swidth = 320;
/// <summary>
/// 缩略图高
/// </summary>
private int _sheight = 250; private Bitmap _image;
private Bitmap _thumbnailimage;
private object _lock = new object();
private object _lock2 = new object();
public string Url
{
set { _url = value; }
}
public int Width
{
set { _width = value; }
}
public int Height
{
set { _height = value; }
}
public int SWidth
{
set { _swidth = value; }
}
public int SHeight
{
set { _sheight = value; }
}
public Bitmap Image
{
get { return _image; }
}
public Bitmap ThumbnailImage
{
get { return _thumbnailimage; }
}
public string DocText
{
get;
set;
}
public int runtime
{
get;
set;
}
public GHtmlToImage()
{
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
}
/*
[STAThreadAttribute]
static void Main()
{
}
*/
public void Init()
{
lock (_lock)
{
Thread _thread = new Thread(new ThreadStart(_GenerateHtmlToImgImage));
_thread.Name = "Galsun.Fcx.htmlToImage";
_thread.SetApartmentState(ApartmentState.STA);
_thread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
_thread.Start();
_thread.Priority = ThreadPriority.Highest;
TimeSpan ts = new TimeSpan(0, 0, 0, 30);
_thread.Join();
GC.Collect();
GC.Collect();
}
}
[STAThread]
private void _GenerateHtmlToImgImage()
{
Monitor.Enter(this);
try
{
#region 普通
WebBrowser _WebBrowser = new WebBrowser();
_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
//_WebBrowser.ProgressChanged += new WebBrowserProgressChangedEventHandler(WebBrowser_ProgressChanged);
_WebBrowser.ScrollBarsEnabled = false;
_WebBrowser.Navigate(_url);
System.Windows.Forms.Timer _tm = new System.Windows.Forms.Timer();
_tm.Interval=1000;
_tm.Tick += new EventHandler(Time_Tick);
_tm.Enabled = true;
//Application.SetCompatibleTextRenderingDefault(false);
Application.Run();
//Application.EnableVisualStyles();
_WebBrowser.Dispose();
#endregion #region 新模式
/*
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainForm _form = new MainForm();
_form._url = _url;
_form._width = _width;
_form._height = _height;
_form._swidth = _swidth;
_form._sheight = _sheight;
_form.Width = _width;
_form.Height = _height;
Application.Run(_form);
_image = _form._image;
_thumbnailimage = _form._thumbnailimage;
*/
#endregion
}
finally
{
Monitor.Exit(this); }
}
private void Time_Tick(object sender, EventArgs e)
{
if (runtime > 0)
{
Thread.Sleep(100);
Application.ExitThread();
}
}
private void WebBrowser_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e)
{
WebBrowser _webBrowser = (WebBrowser)sender;
if (e.CurrentProgress == e.MaximumProgress && _webBrowser.ReadyState == WebBrowserReadyState.Complete)
{
Application.ExitThread();
}
}
private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
Monitor.Enter(this);
try
{
WebBrowser _webBrowser = (WebBrowser)sender;
if (_webBrowser.ReadyState == WebBrowserReadyState.Complete)
{
DocText = _webBrowser.DocumentText;
if(_webBrowser.Document.Body.ScrollRectangle.Height> _height)
{
_height=_webBrowser.Document.Body.ScrollRectangle.Height;
}
_webBrowser.ClientSize = new Size(_width, _height);
//_webBrowser.ScrollBarsEnabled = false;
//Application.DoEvents();
_image = new Bitmap(_webBrowser.Bounds.Width, _webBrowser.Bounds.Height);
_webBrowser.BringToFront();
_webBrowser.DrawToBitmap(_image, _webBrowser.Bounds);
_thumbnailimage = (Bitmap)_image.GetThumbnailImage(_swidth, _sheight, null, IntPtr.Zero);
runtime++;
}
}
finally
{
Monitor.Exit(this);
}
}
}
另外你其它帖子发的不是.NET专区,我就不去搀和了。