DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: xkjdf02
今日帖子: 1
在线用户: 7
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 cenunus (cenunus) ★☆☆☆☆ -
普通会员
2017/7/27 16:29:26
标题:
内存泄露,请帮忙看看代码 浏览:1403
加入我的收藏
楼主: type
  TBmpArr = array of PByteArray;


procedure TForm1.btn1Click(Sender: TObject);
begin
  TThread.CreateAnonymousThread(
  procedure
  var
    I:Integer;
  begin
    for I := 0 to 9999 do
    begin
      Sleep(50);
      获取指定窗口信息;
      lbl1.Caption:=IntToStr(I+1);
    end;
  end
  ).Start;
end;

procedure TForm1.SetBmpArr(bitmap: TBitmap; var BmpArr: TBmpArr);
var
  Y:Integer;
begin
  SetLength(BmpArr,bitmap.Height);
  for Y := 0 to bitmap.Height-1 do
  begin
    BmpArr[Y]:=bitmap.ScanLine[Y];
  end;
end;

function TForm1.获取指定窗口信息: TStringList;
var
  R:TRect;
  bitmap:TBitmap;
  DC:HDC;
  ScreenCanvas:TCanvas;
  BmpArr:TBmpArr;
  I:Integer;
begin
  try
    //GetWindowRect(HWND,R);
    R.Width:=1440;
    R.Height:=900;
    bitmap:=TBitmap.Create;
    bitmap.PixelFormat := pf24bit;
    bitmap.Width:=R.Width;
    bitmap.Height:=R.Height;
    DC:=GetDC(0);
    ScreenCanvas:=TCanvas.Create;
    ScreenCanvas.Handle:=DC;
    bitmap.Canvas.CopyRect(Rect(0,0,R.Width,R.Height),ScreenCanvas,Rect(0,0,R.Width,R.Height));
    SetBmpArr(bitmap,BmpArr);
    //result:=获取全部信息(BmpArr,bitmap.Height,bitmap.Width);
  finally
    ScreenCanvas.Free;
    bitmap.Free;
    ReleaseDC(0,DC); //释放DC
    SetLength(BmpArr,0);
  end;
end;

以上代码内存泄露非常厉害,怀疑是SetLength(BmpArr,0)没有正确释放,因为BmpArr[Y]:=bitmap.ScanLine[Y]时,bmparr[Y]中存放的指针没有被释放,请各位大侠帮忙看看,多谢!
----------------------------------------------
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2017/7/27 16:42:32
1楼: 1 线程中访问 UI 是大忌,不过不会有内存泄露
2 你如何证明有泄露?别跟我说什么 任务管理器。

任务管理器不能证明任何东西。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 cenunus (cenunus) ★☆☆☆☆ -
普通会员
2017/7/27 16:56:31
2楼: 上面访问ui的代码时临时写的,主要就是看进度的,确实是看任务管理的内存占用,内存占用是飞速增长,很快系统就非常卡慢了。。。。。
----------------------------------------------
作者:
男 wk_knife (wk_knife) ★☆☆☆☆ -
盒子活跃会员
2017/7/27 17:14:18
3楼: 为啥每次重新申请bitmap,把它放在1-9999的循环外面不也可以.另外bmparr不也可以放外面。
----------------------------------------------
-
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2017/7/27 17:21:40
4楼: ReportMemoryLeaksOnShutdown := True;

然后你运行一次你怀疑的代码 退出即可。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 cenunus (cenunus) ★☆☆☆☆ -
普通会员
2017/7/27 17:38:35
5楼: 程序运行前,内存占用5M多,循环100次后,达到299M,这正常吗?
----------------------------------------------
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2017/7/27 17:39:29
6楼: 不信就算了。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 cenunus (cenunus) ★☆☆☆☆ -
普通会员
2017/7/28 1:02:11
7楼: 去掉这行bitmap.Canvas.CopyRect(Rect(0,0,R.Width,R.Height),ScreenCanvas,Rect(0,0,R.Width,R.Height));就没有内存泄露了,似乎bitmap的图像缓冲区没有释放掉?
----------------------------------------------
作者:
男 bdl1 (bdl1) ▲▲▲▲▲ -
普通会员
2017/7/28 11:41:31
8楼: 在berlin下,win32平台测试,确实存在这个问题。
----------------------------------------------
-我的博客
作者:
男 cenunus (cenunus) ★☆☆☆☆ -
普通会员
2017/7/28 13:21:22
9楼: 自己解决了,代码如下
procedure TForm1.btn1Click(Sender: TObject);
begin
  TThread.CreateAnonymousThread(
  procedure
  var
    I:Integer;
  begin
    bitmap:=TBitmap.Create;
    ScreenCanvas:=TCanvas.Create;
    N:=0;
    for I := 0 to 999 do
    begin
      //Sleep(1000);
      获取指定窗口信息;
      lbl1.Caption:=IntToStr(I+1);
    end;
    ReleaseDC(0,DC);
    SetLength(BmpArr,0);
    ScreenCanvas.Free;
    bitmap.Free;
  end
  ).Start;
end;

procedure TForm1.SetBmpArr(bitmap: TBitmap; var BmpArr: TBmpArr);
var
  Y:Integer;
begin
  if Length(BmpArr)>0 then SetLength(BmpArr,0);
  SetLength(BmpArr,bitmap.Height);
  for Y := 0 to bitmap.Height-1 do
  begin
    BmpArr[Y]:=bitmap.ScanLine[Y];
  end;
end;

function TForm1.获取指定窗口信息: TStringList;
var
  R:TRect;

  I,J:Integer;
begin
  try
    DC:=GetDC(0);
    bitmap.Assign(nil);
    //GetWindowRect(HWND,R);
    bitmap.Canvas.Lock;
    R.Width:=1440;
    R.Height:=900;
    bitmap.PixelFormat := pf24bit;
    bitmap.Width:=R.Width;
    bitmap.Height:=R.Height;
    ScreenCanvas.Handle:=DC;
    bitmap.Canvas.CopyRect(Rect(0,0,R.Width,R.Height),ScreenCanvas,Rect(0,0,R.Width,R.Height));
    //N:=N+1;
    //bitmap.SaveToFile(IntToStr(N) + '.bmp');
    SetBmpArr(bitmap,BmpArr);
    //result:=获取全部信息(BmpArr,bitmap.Height,bitmap.Width);
  finally
    bitmap.Canvas.Unlock;
  end;
end;

要注意的是这句bitmap.Assign(nil),如果没有这句,每次抓的图都是一样的!
关于对象的创建放不放在循环内,昨天我测试了一下,放在循环内也不会造成占用内存疯狂增长,只要也把对象释放语句放在循环内就行了,不过还是放在循环外面顺眼一些。
----------------------------------------------
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行197.0215毫秒 RSS