c ++如何测试堆中的某些内存是否空闲?

时间:2015-04-23 10:24:35

标签: c++ pointers memory heap

我有一些代码:

int *ip = new int;

*ip = 42;
cout << *ip << endl;
cout << ip << endl;

delete ip;
cout << *ip << endl;
cout << ip << endl;

输出结果为:

42
0x100105400
42
0x100105400

从指针的值和它所指向的内存上的值,我想我不知道ip指向的堆中的内存位是否是空闲的?

我知道如果我在代码之后再次添加delete ip;,编译器将抛出错误。这将是一个很好的证据,表明记忆是免费的。

但是,我怎样才能测试它是否是和平的,所以我可以用它作为判断代码中进一步操作的条件?

3 个答案:

答案 0 :(得分:0)

  

但是,我怎样才能测试它是否是和平的,所以我可以用它作为决定我代码中进一步操作的条件?

释放内存不会改变指针的值,并且不一定会改变它指向的内存(无论如何它都不应该尝试访问)。

在删除指针时,您应该将指针设置为nullptr,然后您可以检查它是否为nullptr,以查看它是否已被释放。

示例:

int* ip = new int;

*ip = 42;

delete ip;
ip = nullptr;

// ...

if (ip) {
    delete ip;
    ip = nullptr;
}

答案 1 :(得分:0)

如果您的代码取决于特定内存是否空闲,则可能存在一些设计问题。但是,如果你确实想要测试,你可以重载operator newoperator delete(及其相应的数组/类版本),以便跟踪在您可用的某些全局数据结构中分配的内存位置程序。下面是一些玩具示例(live on ideone.com),它定义了一个位置new,用于跟踪分配的内存(和大小)。

#include <iostream>
#include <map>

std::map<void*, std::size_t> memory; // globally allocated memory map
struct tag {}; // tag for placement new's so we don't overload the global ones

void* operator new(std::size_t size, const tag&)
{
    void* addr = malloc(size);
    memory[addr] = size;
    return addr;
}

void* operator new[](std::size_t size, const tag&) // for arrays
{
    return operator new(size, tag());
}

void operator delete(void *p) noexcept
{
    memory.erase(p);
    free(p);
}

void operator delete[](void *p) noexcept // for arrays
{
    operator delete(p);
}

void display_memory()
{
    std::cout << "Allocated heap memory: " << std::endl;
    for (auto && elem : memory)
    {
        std::cout << "\tADDR: " << elem.first << " "
                  << "SIZE: "  << elem.second << std::endl;
    }
}

bool is_allocated(void* p)
{
    return (memory.find(p) != memory.end());
}

int main()
{
    int *p = new(tag()) int[10];
    char *c = new(tag()) char;

    // test if p is allocated
    std::cout << std::boolalpha << "Allocated: "
              << is_allocated(p) << std::endl;

    // display the allocated memory
    display_memory();

    // remove p
    delete[] p;

    // test again if p is allocated
    std::cout << std::boolalpha << "Allocated: "
              << is_allocated(p) << std::endl;

    display_memory();

    // remove c
    delete c;

    display_memory();
}

编辑:我意识到上面的代码可能存在一些问题。在函数

void operator delete(void *p) noexcept
{
    memory.erase(p);
    free(p);
}

memory.erase(p)也会调用operator delete,因此您最终可能会遇到一些令人讨厌的递归(出于某种原因,上面的代码只会输入一次递归)。修复方法是为使用std::map memory而不是全局malloc/free的{​​{1}}编写自定义分配器。

答案 2 :(得分:0)

为了完整起见,这里是Doug Lea的免费商店实施页面的链接:http://g.oswego.edu/dl/html/malloc.html

在第一个图表的内存布局中,您可以看到每个分配块的用户数据前面都有记账信息,其中包括&#34; in-use&#34;旗。这些块形成一个链表:从给定的块中,可以在此之后到达所有块(实际上,也可以在此之前)。

知道数据大小和对齐要求,可以猜测给定系统,该信息可能与返回的指针有关;在我的x86_64-pc-cygwin上,状态字节是返回地址前的8个字节,&#34;在使用中&#34; flag是第一个字节的2位。

虽然看起来很有希望,但有一个问题:我可以看到一个delete()coalescs相邻的块,以便簿记信息仅在融合块的开头有效:如果你有两个指针p1,p2指向按顺序分配的免费商店中的内存,并且您再次按顺序删除,p2的簿记位置的内存不会刷新以反映p2已被释放。相反, p1 之前的簿记区域现在指示以下内存块具有组合的单个块的大小。

为了找出给定指针指向的内存是否已被释放,必须遍历内存块的链接列表,可能是从在其他任何内容之前分配的虚拟对象开始。当然可能,但不可取,不健全。 @ vsoftco的想法要好得多。

最后并非最不重要的是:总是从main返回int的人可能会抱怨所有这些都是UB。他们是对的。