2015-12-07 19 views
-1

各种来源似乎不鼓励类型常量,而倾向于更多面向对象的技术。例如DelphiBasics,它们被描述为“非常奇怪”,并且StackOverflow Question给出了一些关于它们可能被使用的背景的背景。下面是一个真正的常量和类型常量的例子。可以键入常量是内存泄漏的来源吗?

const 
    RESULTS_BASIC1  = $01; // True constant 
    RESULTS_BASIC2: BYTE = $01; // Typed constant 

我正在使用Delphi 7和FastMM4,并报告了单个TCriticalSection的泄漏。使项目选项的详细地图文件后,FastMM4堆栈跟踪显示是这样的:

402E58 [StConst][StConst][@GetMem] 
40454B [WinConvert][WinConvert][d_len] 
404926 [Main][Main][EXAMPLE_TYPED_CONSTANT1] 
... 

如果我再删除该类型的常数,同样TCriticalSection报告为被泄露......在接下来的类型化不变!在逐渐放慢一种类型的常量之后,我仍然没有接近泄漏的“真实”来源。

两个相关的问题:

1)请问一个类型不变(这实际上是一个内存地址的变量)是内存泄漏的真正原因? FastMM4能否报告错误泄漏?

2)真的应该避免输入常量,如果是的话,推荐的选择是什么?例如,假设我使用的经过处理器计时单位计数(无符号的32位整数):

dwElapsed := (GetTickCount() - m_dwLastFlashCheck); 
if (dwElapsed > 2000) then 
    begin 
    m_dwLastFlashCheck := GetTickCount(); 
    DoSomething(); 
    end; 

似乎自然定义一个“恒定”,如:

RATE_FLASH: DWORD = 2000; 
// ... 
if (dwElapsed > RATE_FLASH) then 
// etc 
+0

相关,[delphi string leak](http://stackoverflow.com/q/5423329/576719)。 –

+1

在你最后的问题中,不需要使用类型常量。一个真正的常量“RATE_FLASH = 2000”就足够了。编译器通常会找到正确的翻译。在某些情况下,您可以使用'RATE_FLASH = DWORD(2000)'使其更清晰。 –

+0

@LURD:对!我将在未来使用你建议的'RATE_FLASH = DWORD(2000)',因为这看起来既清晰又真实。 – AlainD

回答

4

这种常数是位于可执行映像中。因此,它们在模块加载时分配,当模块卸载时释放,因此它们不能泄漏。

你的常量不是问题。你显然有一个糟糕的解码堆栈跟踪。例如,如果你可以使用madExcept来解码堆栈跟踪,那么我怀疑你会得到更好的堆栈跟踪。这也可能是由于过时的映射文件造成的。

底线是你不应该有一个数据地址作为堆栈上的返回地址。所以,堆栈跟踪必须是错误的。


现在,您还链接到建议不要使用类型常量的引用。但是你正在错误地阅读这些引用。在许多情况下,键入的常量是完全有效的方法。

有什么值得怀疑的是可指定键入的常量 - 任何名称为矛盾修饰词的特征应视为极度怀疑。事实证明,可分配的类型常量仅在实现中发生。当引入类型常量时,由于当天的系统不支持内存保护,因此不能将其置于只读内存中。引入内存保护时,编译器得到了增强,以支持类型常量的两种模式:只读和可分配。请避开可赋值类型常量,但只读类型常量非常合理。

+0

好吧,将使用madExcept进行调查。安装它,但需要提醒自己如何使用它。 – AlainD

+0

您需要让FastMM使用其堆栈跟踪功能。 IIRC。 –

+0

你是对的,但AFAICS我已经通过在FastMM4的.inc文件中定义'FullDebugMode'和'RawStackTraces'来配置FastMM4来使用它的堆栈跟踪功能。通过启用这些选项和详细的映射文件,FastMM4会报告问题中报告的轨迹,例如。 '[主要] [主要] [EXAMPLE_TYPED_CONSTANT1]'。 – AlainD