Deep profile malloc, new

If I ask you: what is the difference between malloc and new? Talk about malloc, the more the better?

  Both malloc and new are based on the corresponding space created on the heap. This space will not be released unless the process ends, so free and delete are required to release it respectively.

  New can also use new[] to open up a continuous space. Unlike malloc, new also calls the object's constructor when opening up space for an object of a class.

  Similarly, delete and delete[] will also call the corresponding destructor when targeting the space of an object of a class, while malloc and free will not.

 

Is that enough? ? ? ?

 

I don't know if it's enough or not, but I think it's better to answer:

 

1. They are not a kind of thing

  new is a keyword given in C++ rules, it is an operator that can be overloaded, and malloc is a function, its purpose is to open up a space on the heap.

  The bottom layer of new is also implemented according to malloc. If you have VS, you can press F11 to enter the new process when debugging.

  It can be found that new and delete are a NULL object, which is allowed. After entering, there will be a judgment. If it is judged that NULL will be returned directly, no error will be reported.

 

  but! ! ! ! The new operator can be overloaded, so. Can it carve up space outside of the heap? ? ?

  absolutely okay!

 

  Because the bottom layer of new was originally implemented according to malloc, OK, I directly overloaded it to make it work in other areas! Can't this be done?

  Therefore, to correct this misunderstanding, new is to open up space on the heap without being overloaded.

 

2. new is Andy Lau.

  We can often see that after each malloc, it is necessary to judge whether the malloc is successful, and if it is unsuccessful, the next operation will not be performed.

  For example the following code:

1 char *p = (char *)malloc(sizeof(char) * 20);
2 if(NULL == p)
3     perror("malloc"),exit(1);

   It's a good habit to deal with when the unexpected happens.

  However, we don't often see the handling of unexpected situations behind new.

  Why? Doesn't new fail?

  Because after new fails, an error will be reported directly, and the compiler will automatically terminate your process.

  One cannot be turned back, the other can be saved.

  Of course, if you want new to return NULL after failure, you need special handling methods:

    1. Add nothrow after new, such as using new(nothrow) A instead of new A.

     2. Overload the new operator, don't forget one of the important features of our C++ - polymorphism.

 

  It should be specially noted: the underlying implementation of new under each compiler is different, so whether to return NULL or report an exception depends on the underlying specific implementation. Therefore, when using a certain undefined function or When it comes to keywords, the exploration of the bottom layer is the top priority.

 

3. new[ ] is treated differently

  When new[ ] is an array of objects of a class with constructors and destructors, the space opened up by new[ ] is to open up an additional four-byte area in the header to record the number of objects.

  However, when the space for new[ ] is an array of primitives, or an array of objects of a class without a destructor, this area does not appear.

  让我们用代码探索一下:(这里我使用VS2013编辑代码)

  

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class Test_1 //构造+析构
 6 {
 7 public:
 8     Test_1()
 9         :mem(1)
10     {}
11 
12     ~Test_1()
13     {
14         cout << "Test_1" << endl;
15     }
16 private:
17     int mem;
18 };
19 
20 class Test_2 //无析构
21 {
22 public:
23     Test_2()
24         :mem(2)
25     {}
26 private:
27     int mem;
28 };
29 
30 int main()
31 {
32     Test_1 *p1 = new Test_1[10];
33     Test_2 *p2 = new Test_2[10];
34 
35     int *p3 = new int[10];
36     system("pause");
37     return 0;
38 }

  

  我设立了一个带析构的类Test_1和一个不带析构的类Test_2,我们再看new 的底层实现:

1 void *__CRTDECL operator new[](size_t count) _THROW1(std::bad_alloc)
2     {    // try to allocate count bytes for an array
3     return (operator new(count));
4     }

  

  可见new[ ] 底层调用了函数operator new ,并赋予一个参数count,用于记录开辟的空间大小。

  让我们看一下对于3次调用new的count大小:

 

Test_1:

 

 

Test_2:

 

 

int:

 

 

 

  由此可见,对于带析构函数的类,new[ ]在开辟空间时会多开辟4个字节的空间,用于什么呢?我们来看一下内存。

    

  可以很明显看到,p1指针所在位置前一个地址的值为0x0000000a,化为10进制值为10,可知其就是为了保存所需要开辟的对象有多少个。

  可以总结出:这里特地腾出的空间是专门为类的析构函数服务的,每次开辟空间的指针在释放空间时,都会根据空间前四个字节内的值来得出——是否需要调用析构函数?以及,调用多少次析构函数?

  

四.malloc所开辟的,可不止这么点点。

  有没有想过?malloc 开辟一块堆上空间后,系统怎么去管理它?下次需要开辟空间时,系统怎么知道这块区域已被用?

  没事,系统总会有办法的。

  malloc 的作用,不是去堆上直接取,而是向操作系统申请这块空间的使用权,等CPU响应这个申请,然后执行相应的操作,当然,操作系统为了更好地管理malloc 完的这块空间,它会选择给这块空间之前加一个结构体,也就是一个装有这块空间的属性的包,在这块空间后一位的地址处内容是0xFCFCFCFC,可以理解为是这块空间的终止符,让系统能分辨出这块空间申请到何处。

  malloc 有关的结构体:

1 typedef struct s_block *t_block;
2 struct s_block {
3 size_t size; /* 数据区大小 */
4 t_block next; /* 指向下个块的指针 */
5 int free; /* 是否是空闲块 */
6 int padding; /* 填充4字节,保证meta块长度为8的倍数 */
7 char data[1] /* 这是一个虚拟字段,表示数据块的第一个字节,长度不应计入meta */
8 };

 

  系统会根据当前操作系统空间块的分配算法,分配给malloc 合适的空间并附上结构体和收尾标识以助于管理。

  所以,malloc 出来的空间会大于用户可见的空间。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324799104&siteId=291194637