【问题标题】:How can I quickly clear a record of simple types?如何快速清除简单类型的记录?
【发布时间】:2011-07-27 10:25:17
【问题描述】:

我有一个这样定义的结构:

const
  MaxSignalRecords=255;
type
  TSignalRecord=record
   signal1  : integer;
   signal2  : integer;
   signal3  : integer;
   signal4  : integer;
   signal5  : integer;
   signal6  : integer;
   bsignal1 : Boolean;
   bsignal2 : Boolean;
   bsignal3 : Boolean;
   bsignal4 : Boolean;
   bsignal5 : Boolean;
   bsignal6 : Boolean;
  end;

TListSignals = Array[0..MaxSignalRecords-1] of TSignalRecord;

这种结构用于在这样的算法中进行数千次计算:

for i:=1 to 900000 do
begin
  CleartheList(MyList);
  DotheMath(MyList);
  DotheChart(MyList);
end;

我正在寻找一种快速的方法来将我的 TListSignals 的值初始化为 0 和 false。

现在我正在使用这个:

procedure ClearListSignals(var ListSignals:TListSignals);
var
  i :Integer;
begin
  for i := 0 to MaxSignalRecords - 1 do
  with ListSignals[i] do
  begin
   signal1   :=0;
   signal2   :=0;
   signal3   :=0;
   signal4   :=0;
   signal5   :=0;
   signal6   :=0;
   bsignal1  :=false;
   bsignal2  :=false;
   bsignal3  :=false;
   bsignal4  :=false;
   bsignal5  :=false;
   bsignal6  :=false;
  end;
end;

如何提高ClearListSignals 过程的性能?

【问题讨论】:

    标签: delphi


    【解决方案1】:

    您可以使用位于Windows 单元中的ZeroMemory 过程。

    var
      MyList : TListSignals;
    begin
         ZeroMemory(@Mylist,SizeOf(MyList));
    end;
    

    【讨论】:

    • 所以如果我要读取任何 ListSignals[i].signal1 的值,这将等于 0?避免初始分配的好方法。
    • @Altar 问答仅用于简单类型的记录。
    • 我想 ZENsan 的回答更正确。需要使用Default 并且不能直接访问内存
    • @SolarWind,如果记录中包含有值的字符串,ZeroMemory 会导致内存泄漏。您可以在调用 ZeroMemory 之前先调用记录上的 Finalize() 以释放字符串。
    • @dan-gph-Salvador 在他的记录中没有显示任何字符串,因此 zeromemory 在这种情况下有效。
    【解决方案2】:

    你应该使用标准的 Delphi 语言函数 Default()!

    const
      MaxSignalRecords = 255;
    
    type
      TSignalRecord = record
        ...
        bsignal6 : Boolean;
      end;
    
    var
      X: TSignalRecord
    ...
    X := Default(TSignalRecord);
    ...
    

    而且没有 hack.. 就像之前建议的那样..

    【讨论】:

    • Default() 是 introduced in Delphi 2009。
    • 这似乎是最优雅的方式。我认为如果你有一个记录的构造函数,它应该为你清零内存,这样记录更像类。
    【解决方案3】:
    FillChar(ListSignals, SizeOf(ListSignals), 0);
    

    【讨论】:

    • ZeroMemory 只是 FillChar(,,0) 的一个包装器。
    • ZeroMemory 是使用 FullChar 的内联,但 ZeroMemory 的读取效果要好得多
    • FillChar 在System 中定义,使其独立于平台,ZeroMemory 仅适用于 Windows。
    • FillChar 也适用于 Laazarus 和 Free Pascal 以及 Mac OS X。
    【解决方案4】:

    除了关于FillChar 和ZeroMemory(无论如何在内部只是调用FillChar)的内容之外,您可以使用bsignal: set of 1..6; 而不是单独的布尔值来减小记录的大小,这应该会稍微加快清除速度.

    【讨论】:

    • +1 因为这是个好主意。布尔值将在 4 或 8 个字节的边界上对齐,因此这非常浪费空间,因此在这种情况下会加快速度。
    • 真的吗,@A.Bouchez?我认为布尔值在 1 字节边界上对齐。您是说问题中记录的总大小是 48 而不是 30?
    • 布尔值将根据编译器对齐开关对齐,除非记录被打包。另外,现在 RAM 很便宜,所以我不会太担心浪费空间。
    • @Rob:你是对的:使用 sizeof(TSignalRecord) 你会得到...... 32,即会有 1 字节对齐。然后整个记录大小为packed record,您将得到 sizeof(TSignalRecord)=30。使用 1..6 组,您将拥有 sizeof(TSignalRecord)=28。
    • 空间浪费的问题不是 RAM 的货币成本,而是缓存使用不当所带来的速度影响。但这在这里并不那么相关,因为布尔值的对齐方式为 1。
    【解决方案5】:

    您可以使用 SecureZeroMemory

    为了避免不希望的影响 优化编译器,使用 SecureZeroMemory 函数。

    SecureZeroMemory 函数填充一个 带零的内存块。它是 设计为更安全的版本 零内存。

    使用这个函数代替 ZeroMemory 当你想确保 您的数据将被覆盖 及时,因为编译器可以优化 通过删除它来调用 ZeroMemory 完全。

    http://msdn.microsoft.com/en-us/library/aa366877%28v=vs.85%29.aspx

    LE:如果您的版本不包含它,您可以在这里了解如何在 Delphi 中使用它:

    Using SecureZeroMemory in Delphi

    【讨论】:

    • SecureZeroMemory 顾名思义,是一项安全功能。它不适用于一般用途。优化编译器仅在检测到内存未在以后重用时才删除对 ZeroMemory 的调用——这意味着清除它没有意义。但是,内存可能包含密码,但以后不会重复使用。然后,您仍然希望确保从内存中清除密码,以免它出现在内存转储中,或者被黑客攻击访问。在 OP 的情况下,绝对不需要使用SecureZeroMemory。尽管了解该功能很有用。
    • 问答仅供简单类型记录
    猜你喜欢
    • 2018-01-24
    • 2018-01-25
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    相关资源
    最近更新 更多