学院网站建设的现状分析,住房和城乡建设部网站 事故,邵东网站建设,跳网站查询的二维码怎么做的C内存池 重载 new 和 delete 运算符C内存池使用内存池的目的逐步实现内存池 重载 new 和 delete 运算符
实际开发中#xff0c;重载new和delete的主要目的是实现内存池。内存池在高性能的服务程序中很常用。点击浏览重载 new 和 delete 运算符的内容#xff0c;建议先看这部… C内存池 重载 new 和 delete 运算符C内存池使用内存池的目的逐步实现内存池 重载 new 和 delete 运算符
实际开发中重载new和delete的主要目的是实现内存池。内存池在高性能的服务程序中很常用。点击浏览重载 new 和 delete 运算符的内容建议先看这部分。
C内存池
内存池是预先分配的内存空间。程序启动的时候先向系统申请一大块连续的空间。在程序中如果需要用内存 从内存池中借一块小的空间出来用完了再还回去。说白了如果沒有内存池直接向系统借如果有内存池就向内存池借。 程序在运行的过程中如果内存池太小了可以扩展。但有一个原则每次都会向系统申请一大块连续的内存空间。
使用内存池的目的
目的主要有两个
提升分配和归还的速度
对高性能的服务程序来说频繁的new和delete也算浪费资源。
减少内存碎片
碎片多了系统管理内存的效率就会下降系统的性能也会下降。
逐步实现内存池
#include iostreamusing namespace std;class Car
{public:int speed;float acceleration;Car(int sp, float acc){speed sp, acceleration acc; cout ~~ 类的构造 speed: speed acceleration: acceleration ~~ endl;}~Car() {cout ~~ 调用析构 ~~ endl;}
};int main() {Car* p new Car(320, 4.6);cout p的地址 p \nspeed: p-speed acceleration: p-acceleration endl;delete p;return 0;
}在上面这段代码中Car类有两个类型分别是int和float的成员变量所以用Car类创建的对象占用的内存空间是8字节。 我打算预先向系统申请连续的18字节的内存空间如下图 也就是说内存池的大小是18字节。 组织数据的方法是标志位1个字节图中的0号、9号字节表示后面的空间是否被占用。后面8个18号、1017号字节刚好可以存放1个Car类对象。 标志位的取值只有0和10表示空闲1表示占用。故这18个字节的内存池能存放2个Car对象。 当需要为Car对象分配内存的时候先判断标志位是否被占用若没有被占用就把标志位后面的这个内存地址返回。 了解以上这些知识后来看一段示例代码
#include iostreamusing namespace std;class Car
{public:int speed;float acceleration;Car(int sp, float acc){speed sp, acceleration acc; cout ~~ 类的构造 speed: speed acceleration: acceleration ~~ endl;}~Car() {cout ~~ 调用析构 ~~ endl;}void* operator new(size_t size){cout 调用类的重载 new: size 字节 endl;void* ptr malloc(size);cout 申请的地址是 ptr endl;return ptr;}void operator delete(void* ptr){cout 调用了类的重载 delete endl;if (ptr 0) return;free(ptr);}
};int main() {Car* p new Car(320, 4.6);cout p的地址 p \nspeed: p-speed acceleration: p-acceleration endl;delete p;return 0;
}上面这段代码在C——内存池_1也用到了现在在此基础上实现简单的内存池。
首先内存池需要一个指针来存放它的起始地址。内存池就是一块内存没有数据类型的说法用什么类型的指针都可以。在此示例中用字符更合适因为字符指针1就是偏移1个字节。
声明指针用于存放内存池的起始地址定义初始化内存池的函数定义释放内存池的函数
接下来修改分配内存的重载函数void* operator new(size_t size)向内存池中申请内存。池中只有2个位置判断标志位哪个空闲就返回哪一块。如果没有空闲维位置可以返回空地址也可以直接向系统申请内存。 修改申请内存的重载函数释放内存的函数void operator delete(void* ptr)也一并在下方给出代码如下
#include iostream
#include cstringusing namespace std;class Car
{public:int speed;float acceleration;static char* m_pool; // 内存池的起始地址为什么是静态变量后面有提到static bool initpool() // 初始化内存池的函数{m_pool (char*)malloc(18); // 向系统申请18字节的内存if (m_pool 0) return false; // 若申请失败返回 falsememset(m_pool, 0, 18); // 把内存池中的内容初始化为 0cout 内存池的起始地址 (void*)m_pool endl;return true;}static void freepool() // 释放内存池的函数{if(m_pool 0) return; // 如果内存池为空无需释放直接返回free(m_pool); // 把内存池归还给系统cout 内存池已释放 endl;}Car(int sp, float acc){speed sp, acceleration acc; cout ~~ 类的构造 speed: speed acceleration: acceleration ~~ endl;}~Car() {cout ~~ 调用析构 ~~ endl;}// 类的静态成员函数 static 所以要把 m_pool 声明为静态变量 初始化函数和释放函数也要声明为 static// C——内存池_1 这篇文章的最后有讲到这个点void* operator new(size_t size){if(m_pool[0] 0) // 判断第一位是否空闲 也就是要看内存空间 m_pool 的第一位的标志位 m_pool[0] 是否等于 0{cout 分配了第一块内存 (void*)(m_pool 1) endl;m_pool[0] 1; // 把第一位置标记为已分配return m_pool 1; // 返回第一个用于存放对象的地址}if(m_pool[9] 0) // 判断第二位是否空闲{cout 分配了第二块内存 (void*)(m_pool 10) endl;m_pool[9] 1; // 把第一位置标记为已分配return m_pool 10; // 返回第一个用于存放对象的地址}// 若两个位置都不可用就直接向系统申请内存void* ptr malloc(size); // 向系统申请内存cout 向系统申请到的内存地址 ptr endl;return ptr;}void operator delete(void* ptr){if(ptr 0) return; // 若传进来的地址为空直接返回。if(ptr m_pool 1) // 若传进来的地址是内存池的第一个位置{cout 释放第一块内存 endl;m_pool[0] 0; // 把第一个位置标记为空闲return; // 归还内存之后函数应该立即返回}if(ptr m_pool 10) {cout 释放第二块内存 endl;m_pool[9] 0; // 把第二个位置标记为空闲return; // 归还内存之后函数应该立即返回}// 若传进来的地址不属于内存池把它归还系统。free(ptr); // 释放内存}
};// 内存池的指针 m_pool 是静态成员变量需要在 main 函数外面初始化。
char* Car::m_pool 0; // 初始化内存池指针int main() {if(Car::initpool() false) {cout 初始化内存池失败 endl; return -1;}Car* p1 new Car(320, 4.6);cout p1的地址 p1 \nspeed: p1-speed acceleration: p1-acceleration endl;Car* p2 new Car(220, 4.0);cout p2的地址 p2 \nspeed: p2-speed acceleration: p2-acceleration endl;Car* p3 new Car(520, 2.9);cout p3的地址 p3 \nspeed: p3-speed acceleration: p3-acceleration endl;delete p1;Car* p4 new Car(420, 4.4);cout p4的地址 p4 \nspeed: p4-speed acceleration: p4-acceleration endl;delete p2;delete p3;delete p4;Car::freepool(); // 释放内存池return 0;
}如果内存池用完了根据业务的需求一般有三种方法
扩展内存直接向系统申请内存返回空地址
编译运行效果应该如下地址是你PC上开辟的内存地址与我的不同 内存池的起始地址0x56366e051eb0 分配了第一块内存0x56366e051eb1 ~~ 类的构造 speed: 320 acceleration: 4.6 ~~ p1的地址0x56366e051eb1 speed: 320 acceleration: 4.6 分配了第二块内存0x56366e051eba ~~ 类的构造 speed: 220 acceleration: 4 ~~ p2的地址0x56366e051eba speed: 220 acceleration: 4 向系统申请到的内存地址0x56366e052ee0 ~~ 类的构造 speed: 520 acceleration: 2.9 ~~ p3的地址0x56366e052ee0 speed: 520 acceleration: 2.9 ~~ 调用析构 ~~ 释放第一块内存 分配了第一块内存0x56366e051eb1 ~~ 类的构造 speed: 420 acceleration: 4.4 ~~ p4的地址0x56366e051eb1 speed: 420 acceleration: 4.4 ~~ 调用析构 ~~ 释放第二块内存 ~~ 调用析构 ~~ ~~ 调用析构 ~~ 释放第一块内存 内存池已释放 感谢浏览一起学习