我已经编程了很长时间,我看到的程序,当它们内存不足时,会尝试清理并退出,即优雅地失败.我不记得上次我看到一个人真正尝试恢复并继续正常运行.
如此多的处理依赖于能够成功分配内存,特别是在垃圾收集语言中,似乎内存不足错误应归类为不可恢复.(不可恢复的错误包括堆栈溢出等.)
使其成为可恢复错误的令人信服的理由是什么?
language-agnostic memory memory-management exception error-recovery
我目前正在为Windows MSVC++(9.0)应用程序(即异常结构和类型/继承,调用堆栈,错误报告和日志记录等)开发基于异常的错误报告系统.
我现在的问题是:如何正确报告和记录内存不足错误?
当发生此错误时,例如,作为op bad_alloc抛出的错误,new可能存在许多"功能"不可用,主要涉及进一步的存储器分配.通常,我将异常传递给应用程序,如果它已经在lib中抛出,然后使用消息框和错误日志文件来报告和记录它.另一种方式(主要用于服务)是使用Windows事件日志.
我遇到的主要问题是汇编错误消息.
为了提供一些错误信息,我想定义一个静态错误消息(可能是字符串文字,更好的是消息文件中的条目,然后使用FormatMessage)并包含一些运行时信息,如调用堆栈.
这种使用所需的功能/方法也是如此
std::string, std::stringstream, std::ofstream)swprintf_s, fwrite)StackWalk64, MessageBox, FormatMessage, ReportEvent, WriteFile)除了在MSDN上记录,所有这些都在Windows中更多(Win32)或更少(STL)闭源,所以我真的不知道它们在低内存问题下的行为.
为了证明可能存在问题,我写了一个琐碎的小应用程序,引发了一个bad_alloc:
int main()
{
InitErrorReporter();
try
{
for(int i = 0; i < 0xFFFFFFFF; i++)
{
for(int j = 0; j < 0xFFFFFFFF; j++)
{
char* p = new char;
}
}
}catch(bad_alloc& e_b)
{
ReportError(e_b);
}
DeinitErrorReporter();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
抛出两个没有连接调试器的实例(在Release config,VS 2008中),但"没有发生",即没有来自ReportEvent或WriteFile的错误代码我在错误报告中内部使用.然后,使用一个w/o调试器启动一个实例,让他们尝试使用ReportError行上的断点一个接一个地报告错误.对于连接了调试器的实例(正确报告并记录错误,即使使用LocalAlloc没有问题),这也很好!但是taskman展示了一个奇怪的行为,在应用程序退出之前释放了大量内存,我想当抛出异常时.
请考虑可能有多个进程[编辑]和多个线程[/ edit]消耗大量内存,因此释放预先分配的堆空间不是一个安全的解决方案,以避免想要报告的进程的低内存环境错误.
先感谢您!
在C++中,我正在使用boost::shared_ptr并boost::weak_ptr自动删除不再需要的对象.我知道这些工作与引用计数.
在Java中,内存是由垃圾收集器,其consideres管理的内置对象引用为强,WeakReference因为弱和SoftReference在之间(可通过GC收集,但可能还有生存的GC)的东西,这是非常方便的用于缓存对象一段时间,但一旦可用内存不足就将它们丢弃.
所以现在我回到了C++中,我错过了软引用的安慰.我想知道软引用是否适用于引用计数.当清除对象的最后一个强引用,并且仍然有一个软引用时,它什么时候会被删除?我可以想到一些方案,但对我来说似乎都不聪明.
为了防止软引用和引用计数有适当的语义,我想知道这是否已经实现,可能是以一种甚至兼容的方式boost::shared_ptr(或C++ TR1等效std::shared_ptr的方式).
如果两个问题的答案都是否定的,那么对象缓存场景中的替代方案是什么?
编辑: 当然我说的是缓存实际上很有用的情况,因为构造对象的成本很高(想想几次访问数据库和网络查询),但是有太多东西要永远保存它们.