Memory leak detection in Linux (iv) record the size of the leak

Source: Internet
Author: User
Tags assert int size



"Detection of memory leaks in Linux (iii) customized New/delete" The use of C + + 's function overloading makes C + + code easier for New/delete plus statistical code for detecting memory leaks. However, new problems are also introduced.



The current statistical method only counts the number of applications/releases of memory, and does not count the size of each request/release memory.
This method is sufficient for C because the size of the application and release in C is the same, not necessarily in C + +.
Consider the following two scenarios:



(1) The space in which the subclass was applied only freed the parent class


new son;delete pF;


When you construct a subclass, you apply a space that is the size required by the subclass, and then initialize the members of the parent class, and then initialize the members of the child class.



At the time of the destructor, because it is a pointer to the parent class, only the destructor of the parent class is called and the space occupied by the parent class is freed.
Don't you say polymorphic? Since the PF pointer subclass, why not call the subclass's destructor?
Because the premise of polymorphism is virtual function.



Under normal circumstances, the destructor of a class should be written as a virtual function, which, if forgotten, could cause a memory leak.



(2) A space for an array is applied, but only the space of the first element is released


classnewclass[5];delete pA;


Not all of these situations can lead to memory leaks, and if class is a built-in type, such as int, char, there is no problem. For built-in types, there is no memory leak, but there may be other unknown potential problems, so this is still not recommended.
In C + +, class is not limited to built-in types, and if it is a class of its own definition, delete PA simply releases the first item of the array that the PA points to, resulting in a memory leak.



For these reasons, only counting the number of requests/releases can not accurately detect memory leaks, so the file size is also recorded at the time of application/release.



When you write the code, there is no such question, why the application of memory to pass in the required memory size, and release does not need to explain how much memory to release?



That is because at the time of application, the size of the application is recorded in a certain place, released from the corresponding other side to find out the size. So where do you remember it?


There are generally two ways:

1 non-intrusive, the memory allocator first request memory (and the stack with the use), as a record of the user Layer application record (address, size). When the user frees up space, it looks for the table and can tell that the pointer is legitimate in addition to the amount of space that is freed.

2 intrusion, such as the user to request 1byte of memory, and the memory allocator will allocate 5byte of space (32 bits), the front 4byte for the size of the request. When the memory is freed, it is shifted forward by 4 bytes to find the size of the request before releasing it.

Both methods have advantages and disadvantages, the first of which is safe, but slow. The second is fast, but the programmer's pointer control ability is more demanding, a little inadvertently crossed the space information will be destroyed.


The gcc/g++ compiler on our Linux uses an intrusion by default, in order to verify that the address we find is storing the data we want, I wrote this test code:


 
 
#include <iostream>
using namespace std;

#if(defined(_X86_) && !defined(__x86_64))
#define _ALLOCA_S_MARKER_SIZE 4
#elif defined(__ia64__) || defined(__x86_64)
#define _ALLOCA_S_MARKER_SIZE 8
#endif

int main(void)
{
    void * p = NULL;
    int a = 5, n = 1;
    while (a--)
    {
        p = new char[n];
        size_t w = *((size_t*)((char*)p -  _ALLOCA_S_MARKER_SIZE));
        cout<<"w = "<< w <<" n = "<<n<<endl;
        n = n * 10;
    }
    return 0;
}


This is the result of the operation:



w = n = 1



w = n = 10



W = 113 N = 100



W = 1009 N = 1000



W = 10017 N = 10000



When we read the first few bytes of the requested memory, the data looked like the actual application data, but it is always slightly larger. Is this the data we're looking for? How does it relate to the size of the actual application? This should start with the GCC memory allocation strategy.



Suppose now to apply a space size of n, the actual allocated size is m, and the value we read to IS K



(1) When you call malloc to request N-size space, the compiler also allocates _alloca_s_marker_size bytes to store management information for this space. In the 8 bytes of this management information on CentOS 64 I tested, the information on the size of the application space mentioned above is in it. So M=n+_alloca_s_marker_size



(2) In order to reduce memory fragmentation, the size of the application is an integer multiple of a number, measured on the CentOS 64 I tested the number is 16, that is, the actual application size is a multiple of 16. So m= (n+8-1) &0xfffffff0 + 0x10



(3) In order to avoid the application of small memory, there is such a limit, the minimum actual allocation space size is 0x20
m = (n+8-1) &0xfffffff0 + 0x10 if m < 0x20 m = 0x20



(4) Since M must be a multiple of 16, the last four bits of M in binary are always 0 and do not work. So these 4 bits are used to make the standard bit. So there's K = m + 1



Summary m = (n+7) &0xfffffff0 + 0x11, k = m + 1



To prove that the conclusion is correct, I wrote this code:


 
 
#include <iostream>
using namespace std;

#include<assert.h>
#include<ctime>
#include <stdlib.h>

#if(defined(_X86_) && !defined(__x86_64))
#define _ALLOCA_S_MARKER_SIZE 4
#elif defined(__ia64__) || defined(__x86_64)
#define _ALLOCA_S_MARKER_SIZE 8
#endif

int main(void)
{
    void * p = NULL;
    srand(time(0));
    int a = 100000;
    while (a--)
    {
        int n = rand() % 10000;
        p = new char[n];
        size_t w = *((size_t*)((char*)p -  _ALLOCA_S_MARKER_SIZE));
        if ( n <= 8) n = 9;
        int n2 = ((n+7) & 0xFFFFFFF0) + 0x11;
        assert(n2 == w);
    }
    return 0;
}


In fact, we do not care about the size of the caller's application at the time of statistics, but the size of the compiler's actual application and release, i.e. the code is as follows:


 
#include <iostream>
using namespace std;

#include <stdio.h>
#include <malloc.h>

#if(defined(_X86_) && !defined(__x86_64))
#define _ALLOCA_S_MARKER_SIZE 4
#elif defined(__ia64__) || defined(__x86_64)
#define _ALLOCA_S_MARKER_SIZE 8
#endif

size_t count = 0;

extern "C"
{
void* __real_malloc(int c); 
void * __wrap_malloc(int size)
{
    void *p =  __real_malloc(size);
    size_t w = *((size_t*)((char*)p -  _ALLOCA_S_MARKER_SIZE)) - 1;
    count += w;
    cout<<"malloc "<<w<<endl;
    return p;
}

void __real_free(void *ptr);
void __wrap_free(void *ptr)
{
    size_t w = *((size_t*)((char*)ptr -  _ALLOCA_S_MARKER_SIZE)) - 1;
    count -= w;
    cout<<"free "<<w<<endl;
    __real_free(ptr);
}
}

void *operator new(size_t size)
{
    return malloc(size);
}

void operator delete(void *ptr)
{
    free(ptr);
}

int main(void)
{
    count = 0;
    int *p1 = new int(3);
    int *p2 = new int(4);
    cout <<*p1<<‘ ‘<<*p2<<endl;
    delete p1;
    if(count != 0)
        cout<<"memory leak!"<<endl;
    return 0;
}


Now we are testing for the two cases mentioned above:



(1) The space in which the subclass was applied only freed the parent class


 
 
class father
{
    int *p1;
public:
    father(){p1 = new int;}
    ~father(){delete p1;}
};
class son : public father
{
    int *p2;
public:
    son(){p2 = new int;}
    ~son(){delete p2;}
};

int main(void)
{
    count = 0;
    father *p = new son;
    delete p;
    if(count != 0)
        cout<<"memory leak!"<<endl;
    return 0;
}


(2) A space for an array is applied, but only the space of the first element is released


 
class A
{
    int *p1;
public:
    A(){p1 = new int;}
    ~A(){delete p1;}
};

int main(void)
{
    count = 0;
    A *p = new A[5];
    delete p;
    if(count != 0)
        cout<<"memory leak!"<<endl;
    return 0;
}


Analysis:


    • Ease of Access:
function is supported Description
Run-time Check Whether This method requires that the results be known at the end of the run for printing analysis that is generated during the run.
Is it convenient to modify Is The Wrap function is very simple to implement and only needs to be implemented once, which is valid for all files participating in the link
Is it convenient to use Is To turn off this feature, simply remove the link option


Comprehensive


function is supported Description
Whether the C interface can be processed uniformly Whether Each interface of C is required to write the wrapper function separately
Whether the C + + interface can be processed uniformly Is
Whether a memory leak from a dynamic library to a static library can be detected Is Wrap is a link option that works for all files that are linked to and from wrap,__wrap_malloc__wrap_freewhether they are. O,. A or. So


Accuracy


function is supported Description
If there is a situation that cannot be detected Whether
Whether you can navigate to a row Whether
Whether you can determine the size of the leak space Is


Memory leak detection in Linux (iv) record the size of the leak


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.