gpt4 book ai didi

c++ - 有没有更好的方法来实现这种内存管理?

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:57:01 25 4
gpt4 key购买 nike

这是我之前 question regarding exceptions 的后续.

我有一些要维护的遗留代码。它有一个我很难理解的自定义内存管理组件。

我对系统的理解是这样的:

调用函数要求为其分配一些内存,提供所需的初始内存量 (needed) 和最大内存量 (max)。这调用:

base = VirtualAlloc(0, max, MEM_RESERVE, PAGE_NOACCESS);

据我所知保留内存但不提供访问权限。换句话说,如果我尝试写入保留段,我会遇到访问冲突。

然后调用:

VirtualAlloc(base, needed, MEM_COMMIT, PAGE_READWRITE);

这使得 needed 内存量从 base 开始可访问。

当试图检测何时需要访问更多内存时,棘手的部分就来了。我的理解是,系统会尝试在发生访问冲突异常时捕获它们,并在地址上调用 VirtualAlloc 以使内存可访问。

它通过声明以下方法来做到这一点:

unsigned long __cdecl
exceptionCatch(struct _EXCEPTION_RECORD* er, void*, struct _CONTEXT* cr, void*)
{
if( er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION
&& ExtendBuffer( (void*)er->ExceptionInformation[1] ) )
return ExceptionContinueExecution;

return ExceptionContinueSearch;
}

然后,它使用这段特别可怕的代码将其注册为堆栈顶部的异常处理程序(我认为):

void __cdecl SetHandler(bExceptionRegistration& v)
{
__asm
{
mov eax, 8[ebp] ; get exception register record to install
mov ecx, fs:[0] ; get current head of chain

cmp ecx, eax ; should we be at head?
jb search
mov [eax], ecx ; save current head
mov fs:[0], eax ; install new record at head
jmp short ret1
search:
cmp [ecx], eax ; at proper location yet?
ja link
mov ecx, [ecx] ; get next link
jmp search
link:
mov edx, [ecx]
mov [eax], edx ; point to next
mov [ecx], eax
ret1:
}
}

此方法通过在方法作用域中实例化特定类来调用。看起来它只将处理程序应用于当前堆栈上下文;例如,如果异常未传播到当前方法,则调用函数中抛出的异常不会由当前方法处理。

所有这一切的结果是,不仅没有捕获到访问冲突,而且还禁用了当前堆栈顶部的异常处理。我在 exceptionCatch 函数中设置了断点,执行似乎没有进入它。

我想我的主要问题是:

  1. 有什么特别的原因导致它不起作用吗? 编辑:根据我自己的测试和此处的评论,我认为汇编代码是问题所在。
  2. 更重要的是,是否有更好的方法来完成我认为代码试图做的事情?

我不认为像 set_unexpected 这样的东西是可行的,因为内存管理只适用于这个特定的库,客户端应用程序可能(在我们的例子中确实)有它自己的意外异常处理程序。

编辑:

每个堆栈的处理程序的设置和取消设置是通过使用以下类构造函数和析构函数声明类 bExceptionRegistration 来完成的:

bExceptionRegistration :: bExceptionRegistration() : function(exceptionCatch)
{
SetHandler(*this);
}

bExceptionRegistration :: ~bExceptionRegistration()
{
UnsetHandler(*this);
}

因此,要为特定堆栈范围实际设置处理程序,您需要:

void someFunction()
{
bExceptionRegistration er;
// do some stuff here
}

编辑:我猜测可能最合适的解决方案是将代码中的 bExceptionRegistration 声明替换为 __try, __except block 。然而,我希望避免这种情况,因为它在很多地方都存在。

最佳答案

如果没有看到更多代码,我不能 100% 确定这一点。它不会在堆栈顶部注册异常处理程序,但会使用一个技巧在定义 EXCEPTION_REGISTRATION 结构的地方插入异常处理程序。因此,例如(在您的情况下,它的实现方式可能有所不同):

void function3(EXCEPTION_REGISTRATION& handler)
{
SetHandler(handler);
//Do other stuff
}
void function2(EXCEPTION_REGISTRATION& handler)
{
__try
{
//Do something
function3(handler);
}
__except(expression)
{
//...
}
}

void function()
{
EXCEPTION_REGISTRATION handler;
//..Init handler
function2(handler)
}

当您调用 SetHandler 时,它将像在函数范围内一样插入异常处理。所以在这种情况下,当您调用 SetHandler 时,它看起来好像函数中有一个 __try __except block 。

因此,如果 function3 中有异常,函数中的处理程序将首先被调用,如果该处理程序不处理它,将调用 SetHandler 安装的处理程序。

关于c++ - 有没有更好的方法来实现这种内存管理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8352151/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com