2

在 Windows 上,我注意到尝试取消引用指向最近释放的内存的指针会导致崩溃,并被 Visual Studio 捕获,指出内存无效。这正如预期的那样。但是,执行相同的应用程序和代码路径导致取消引用指向最近释放的内存的指针不会立即导致 Linux 崩溃。这向我表明,Linux 内核(或 GNU C++ 运行时)不会很快使释放的内存失效,即使在调试版本中也是如此。应用程序需要更长的时间才能崩溃。是这样吗?如果是这样,我可以强制内存更快地取消映射吗?如果不是,那是怎么回事?

4

2 回答 2

2

你试过http://valgrind.org/吗?它的目的是帮助追踪问题,例如您所描述的问题。

于 2013-10-17T15:55:07.390 回答
2

new/的大多数实现delete不会立即将内存返回给系统,或者至少不会返回较小的块。我很惊讶您的代码仅通过取消引用指向内存的指针就在 Windows 下崩溃了;你确定你没有做更多(例如使用你通过指针读取的值)。

块有多大?许多实现根据块的大小使用不同的策略,并且会立即释放非常大的块。(IIRC,Linux 会mmap 立即对非常大的块执行 a,并在释放它时立即取消映射。当然,如果您在释放和取消引用指针之间重新分配内存,则地址可能在新分配的空间中,并且它不会崩溃。)

最后:映射的粒度是页面,不能指望分配器每次分配都会阻塞一个完整的页面,只是为了在释放时立即使内存失效。(一个页面可能至少为 4K,并且您不希望每次分配 16 个字节时都失去 4K 地址空间。)缺少跟踪所有内存访问(如 ValGrand 或 Purify),并且运行速度慢很多,这是唯一的选择是使用垃圾收集,以确保只要有指向它的指针就不会重新分配内存,并在释放时(即 indeletefree)用可能会导致问题的值完全覆盖它,如果使用 ( 0xDEADBEEF,或其他东西像那样)。即便如此,你也不能真正保证你会崩溃——0xDEADBEEF可能是您认为正在阅读的内容的有效值。(但这确实允许在构造函数中设置一个标志,在析构函数中重置它,并在每个函数中测试它。对于必须积极防御的代码。)

于 2013-10-17T16:32:29.260 回答