【发布时间】:2014-09-11 07:16:03
【问题描述】:
这更像是一个哲学问题。
在 C++ 中,我们有漂亮闪亮的习语 - RAII。但我经常认为它是不完整的。这与我的应用程序可以被 SIGSEGV 杀死的事实不符。
我知道,我知道,像你说的那样的程序格式错误。但令人遗憾的是,在 POSIX(特别是 Linux)上,您可以分配超出物理内存限制并在执行过程中遇到 SIGSEGV,使用正确分配的内存。
你可能会说:“应用程序死了,你为什么要关心那些没有被调用的可怜的析构函数?”。不幸的是,当应用程序终止时,有些资源不会自动释放,例如 文件系统 实体。
我现在非常讨厌设计黑客,为了应对这种情况而破坏良好的应用程序设计。所以,我要的是为这类问题提供一个好的、优雅的解决方案。
编辑:
看来我错了,在 Linux 上的应用程序被内核分页器杀死了。在这种情况下,问题仍然相同,但应用程序死亡的原因不同。
代码sn-p:
struct UnlinkGuard
{
UnlinkGuard(const std::string path_to_file)
: _path_to_file(path_to_file)
{ }
~UnlinkGuard() {
unlink();
}
bool unlink() {
if (_path_to_file.empty())
return true;
if (::unlink(_path_to_file.c_str())) {
/// Probably some logging.
return false;
}
disengage();
return true;
}
void disengage() {
_path_to_file.clear();
}
private:
std::string _path_to_file;
};
void foo()
{
/// Pick path to temp file.
std::string path_to_temp_file = "...";
/// Create file.
/// ...
/// Set up unlink guard.
UnlinkGuard unlink_guard(path_to_temp_file);
/// Call some potentially unsafe library function that can cause process to be killed either:
/// * by a SIGSEGV
/// * by out of memory
/// ...
/// Work done, file content is appropriate.
/// Rename tmp file.
/// ...
/// Disengage unlink guard.
unlink_guard.disengage();
}
成功后我使用文件。失败时,我希望此文件丢失。
如果 POSIX 支持 link()-ing 以前未按文件描述符链接的文件,则可以实现此功能,但没有这样的功能:(。
【问题讨论】:
-
“不幸的是,有些资源在应用程序终止时不会自动释放,例如文件系统实体。” - 嗯,文件描述符在应用程序终止时被内核释放。
-
@Slyps 如果你使用不抛出的
new,它会在失败时返回一个空指针。但是普通的new只会抛出std::bad_alloc。 -
@Angew 只有当进程超出虚拟地址空间时,您才会得到空指针/异常。在
x64这几乎是不可能的。它不会失败,因为new(malloc()) 基于mmap()。而mmap()只是让我们说扩展虚拟地址空间。 -
好的,我按照你的描述做了,我得到的是一个“被杀死”的应用程序,正如我所期望的那样。我在工作中已经这样做了好几次了——运行的东西要么有一个错误,分配的内存比它应该的多,要么根本不适合该硬件上可用的内存,它总是被 OOM-killer 杀死.这与“SIGSEGV”不同。所以我想知道是什么使它成为 SIGSEGV 而不是 OOM 被杀死?它在系统调用中死亡吗?你会尝试用一些魔法代码来抵抗 OOM 杀手吗?
-
提供一个实际示例(最好是代码示例)将有助于显示进程被终止时未释放的资源。 “文件系统实体”真的很模糊。
标签: c++ exception segmentation-fault posix raii