【问题标题】:delphi app freezes whole win7 systemdelphi应用程序冻结整个win7系统
【发布时间】:2011-03-04 07:43:25
【问题描述】:

我有一个简单的程序,可以根据每行单词的长度对文本文件进行排序 这个程序在我基于 xp 的旧机器上运行没有问题 现在我在我的新 win7/intel core i5 机器上运行这个程序,它会冻结整个系统并在完成工作后恢复正常。

我研究了代码并找到了导致冻结的行

就是这行……

caption := IntToStr(i) + '..' + IntTostr(ii);

我已经改成

 caption :=   IntTostr(ii);  //slow rate change

没有冻结

然后我把它改成了

caption :=   IntTostr(i);  //fast rate change

它再次冻结

我的程序代码是

 var tword : widestring;
      i,ii,li : integer;
 begin   
     tntlistbox1.items.LoadFromFile('d:\new folder\ch.txt');
     tntlistbox2.items.LoadFromFile('d:\new folder\uy.txt');
     For ii := 15 Downto 1 Do //slow change
      Begin
        For I := 0 To TntListBox1.items.Count - 1 Do //very fast change
        Begin     
          caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
          tword := TntListBox1.items[i];
          LI := Length(tword);
          If lI = ii Then
          Begin             
            tntlistbox3.items.Add(Trim(tntlistbox1.Items[i]));
            tntlistbox4.items.Add(Trim(tntlistbox2.Items[i]));
          End;
        End;
      End;
    end;

知道为什么吗?以及如何解决? 我用的是delphi 2007/win32

【问题讨论】:

  • TntListBox1 中有多少项?
  • 您是否考虑过在循环过程中使用 TStringLists,然后一步将它们分配给列表框?这可能会更快一些。如果您必须支持 Unicode,您可以在 www.soft-gems.net 找到一个 TWideStringList
  • Uwe : 使用 tWidetringlist 只会加快进程,但不会解决冻结问题。
  • avar:这就是为什么我把它作为评论而不是答案。

标签: delphi windows-7 freeze


【解决方案1】:

这是否发生在表单的事件处理程序中?我猜是的。在这种情况下,“标题”在表格的范围内。表单的标题文本不是由 VCL 管理,而是由 Windows 管理,如果您在循环的每次迭代中都发送一条新的 WM_SETTEXT 消息。

要彻底解释为什么要这样做,需要了解我没有的 Windows 内部知识,但如果我猜测一下,我会说它是这样的:

每次您发送带有新标题的 WM_SETTEXT 消息时,Windows 都会检查以确保它与现有标题不同。如果是,它可以立即退出。这就是为什么不经常更改(仅使用ii)不会减慢系统速度的原因。但如果它确实在每次迭代中都发生了变化,那么 Windows 必须执行某种任务切换才能对其进行更改。

至于为什么这会使整个系统在 Vista 内核(包括 Win7)下而不是 XP 下陷入瘫痪,这完全超出了我的专业领域。但是,如果您尝试将其作为某种进度指示器,则有更好的方法,尤其是当这个循环看起来很紧凑时。

在紧密循环中处理进度更新的最佳方法是计算迭代次数,并且每 X 次只触发一次。 (对于 X 来说,100 或 1000 可能是很好的值,这取决于它运行了多少次以及整个过程需要多快。)这基本上是 ii only 选项所做的。您也可以尝试在表单上放置进度条来衡量进度,而不是通过表单的标题来衡量。

【讨论】:

  • +1 可能这里出了什么问题。我们最近修复了系统中的一个错误,该错误导致我们发送的消息超出消息缓冲区的处理能力,这也导致了看似冻结 (xp) 的系统。
  • 感谢 Mason 的建议,我会尝试改用进度条。是的,它是一个 TForm1.Button1Click() 处理程序。
【解决方案2】:

更改表单的标题会释放大量操作 - 特别是在 Vista 和 Win7 下,Aero 处于活动状态。

快速尝试使用 TLabel 代替显示进度。类似的东西

Label1.caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
Label1.Refresh; // or Repaint

除非您的标签是透明的或在玻璃区域上,否则应该可以解决问题。

最好听从 Mason Wheeler 的建议并使用进度条。由于总迭代次数为15*TntListBox1.items.Count,因此您可以很容易地计算出进度值。

【讨论】:

    【解决方案3】:

    首先:您忘记了 tntlistbox3.items.BeginUpdate/tntlistbox3.items.EndUpdate 调用(对于 tntlistbox4 也是如此)。

    二:Why does my program run faster if I click and hold the caption bar?

    解决方案(示例):

    const
      UpdateInterval = 500; // half a second
    var 
      ...
      LastUpdate: Cardinal;
    begin   
      ... 
      LastUpdate := GetTickCount + 100000; // forces first update
      For ii := 15 Downto 1 Do //slow change
      Begin
        For I := 0 To TntListBox1.items.Count - 1 Do //very fast change
        Begin     
          if (GetTickCount > (LastUpdate + UpdateInterval)) or
             (GetTickCount < LastUpdate) then
            caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
          ...
        end;
      end;
    

    【讨论】:

      猜你喜欢
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-03
      • 1970-01-01
      相关资源
      最近更新 更多