做服务的网站吗,三星网上商城官网,wordpress 3.8页面伪静态化 html,wordpress主题 视频#xff08;1#xff09;在运行过程中#xff0c;MemoryPool内存池可能会有多个用来满足内存申请请求的内存块#xff0c;这些内存块是从进程堆中开辟的一个较大的连续内存区域#xff0c;它由一个MemoryBlock结构体和多个可供分配的内存单元组成#xff0c;所有内存块组… 1在运行过程中MemoryPool内存池可能会有多个用来满足内存申请请求的内存块这些内存块是从进程堆中开辟的一个较大的连续内存区域它由一个MemoryBlock结构体和多个可供分配的内存单元组成所有内存块组成了一个内存块链表MemoryPool的pBlock是这个链表的头。对每个内存块都可以通过其头部的MemoryBlock结构体的pNext成员访问紧跟在其后面的那个内存块。 
2每个内存块由两部分组成即一个MemoryBlock结构体和多个内存分配单元。这些内存分配单元大小固定由MemoryPool的nUnitSize表示MemoryBlock结构体并不维护那些已经分配的单元的信息相反它只维护没有分配的自由分配单元的信息。它有两个成员比较重要nFree和nFirst。nFree记录这个内存块中还有多少个自由分配单元而nFirst则记录下一个可供分配的单元的编号。每一个自由分配单元的头两个字节即一个USHORT型值记录了紧跟它之后的下一个自由分配单元的编号这样通过利用每个自由分配单元的头两个字节一个MemoryBlock中的所有自由分配单元被链接起来。 
3当有新的内存请求到来时MemoryPool会通过pBlock遍历MemoryBlock链表直到找到某个MemoryBlock所在的内存块其中还有自由分配单元通过检测MemoryBlock结构体的nFree成员是否大于0。如果找到这样的内存块取得其MemoryBlock的nFirst值此为该内存块中第1个可供分配的自由单元的编号。然后根据这个编号定位到该自由分配单元的起始位置因为所有分配单元大小固定因此每个分配单元的起始位置都可以通过编号分配单元大小来偏移定位这个位置就是用来满足此次内存申请请求的内存的起始地址。但在返回这个地址前需要首先将该位置开始的头两个字节的值这两个字节值记录其之后的下一个自由分配单元的编号赋给本内存块的MemoryBlock的nFirst成员。这样下一次的请求就会用这个编号对应的内存单元来满足同时将此内存块的MemoryBlock的nFree递减1然后才将刚才定位到的内存单元的起始位置作为此次内存请求的返回地址返回给调用者。 
4如果从现有的内存块中找不到一个自由的内存分配单元当第1次请求内存以及现有的所有内存块中的所有内存分配单元都已经被分配时会发生这种情形MemoryPool就会从进程堆中申请一个内存块这个内存块包括一个MemoryBlock结构体及紧邻其后的多个内存分配单元假设内存分配单元的个数为nn可以取值MemoryPool中的nInitSize或者nGrowSize申请完后并不会立刻将其中的一个分配单元分配出去而是需要首先初始化这个内存块。初始化的操作包括设置MemoryBlock的nSize为所有内存分配单元的大小注意并不包括MemoryBlock结构体的大小、nFree为n-1注意这里是n-1而不是n因为此次新内存块就是为了满足一次新的内存请求而申请的马上就会分配一块自由存储单元出去如果设为n-1分配一个自由存储单元后无须再将n递减1nFirst为1已经知道nFirst为下一个可以分配的自由存储单元的编号。为1的原因与nFree为n-1相同即立即会将编号为0的自由分配单元分配出去。现在设为1其后不用修改nFirst的值MemoryBlock的构造需要做更重要的事情即将编号为0的分配单元之后的所有自由分配单元链接起来。如前所述每个自由分配单元的头两个字节用来存储下一个自由分配单元的编号。另外因为每个分配单元大小固定所以可以通过其编号和单元大小MemoryPool的nUnitSize成员的乘积作为偏移值进行定位。现在唯一的问题是定位从哪个地址开始答案是MemoryBlock的aData[1]成员开始。因为aData[1]实际上是属于MemoryBlock结构体的MemoryBlock结构体的最后一个字节所以实质上MemoryBlock结构体的最后一个字节也用做被分配出去的分配单元的一部分。因为整个内存块由MemoryBlock结构体和整数个分配单元组成这意味着内存块的最后一个字节会被浪费这个字节在图6-2中用位于两个内存的最后部分的浓黑背景的小块标识。确定了分配单元的起始位置后将自由分配单元链接起来的工作就很容易了。即从aData位置开始每隔nUnitSize大小取其头两个字节记录其之后的自由分配单元的编号。因为刚开始所有分配单元都是自由的所以这个编号就是自身编号加1即位置上紧跟其后的单元的编号。初始化后将此内存块的第1个分配单元的起始地址返回已经知道这个地址就是aData。 
5当某个被分配的单元因为delete需要回收时该单元并不会返回给进程堆而是返回给MemoryPool。返回时MemoryPool能够知道该单元的起始地址。这时MemoryPool开始遍历其所维护的内存块链表判断该单元的起始地址是否落在某个内存块的地址范围内。如果不在所有内存地址范围内则这个被回收的单元不属于这个MemoryPool如果在某个内存块的地址范围内那么它会将这个刚刚回收的分配单元加到这个内存块的MemoryBlock所维护的自由分配单元链表的头部同时将其nFree值递增1。回收后考虑到资源的有效利用及后续操作的性能内存池的操作会继续判断如果此内存块的所有分配单元都是自由的那么这个内存块就会从MemoryPool中被移出并作为一个整体返回给进程堆如果该内存块中还有非自由分配单元这时不能将此内存块返回给进程堆。但是因为刚刚有一个分配单元返回给了这个内存块即这个内存块有自由分配单元可供下次分配因此它会被移到MemoryPool维护的内存块的头部。这样下次的内存请求到来MemoryPool遍历其内存块链表以寻找自由分配单元时第1次寻找就会找到这个内存块。因为这个内存块确实有自由分配单元这样可以减少MemoryPool的遍历次数。 
综上所述每个内存池MemoryPool维护一个内存块链表单链表每个内存块由一个维护该内存块信息的块头结构MemoryBlock和多个分配单元组成块头结构MemoryBlock则进一步维护一个该内存块的所有自由分配单元组成的链表。这个链表不是通过指向下一个自由分配单元的指针链接起来的而是通过下一个自由分配单元的编号链接起来这个编号值存储在该自由分配单元的头两个字节中。另外第1个自由分配单元的起始位置并不是MemoryBlock结构体后面的第1个地址位置而是MemoryBlock结构体内部的最后一个字节aData也可能不是最后一个因为考虑到字节对齐的问题即分配单元实际上往前面错了一位。又因为MemoryBlock结构体后面的空间刚好是分配单元的整数倍这样依次错位下去内存块的最后一个字节实际没有被利用。这么做的一个原因也是考虑到不同平台的移植问题因为不同平台的对齐方式可能不尽相同。即当申请MemoryBlock大小内存时可能会返回比其所有成员大小总和还要大一些的内存。最后的几个字节是为了补齐而使得aData成为第1个分配单元的起始位置这样在对齐方式不同的各种平台上都可以工作。 
#ifndef DATA_BLOCK_H_
#define DATA_BLOCK_H_#includeassert.h
#includememory.hclass DataBlock
{
public:DataBlock(size_t capacity){data_  new uint8_t[capacity];capacity_  capacity;len_  0;}~DataBlock(){if (data_){delete[] data_;capacity_  0;len_  0;data_  nullptr;}}uint8_t* Data(){return data_;}size_t Length(){return len_;}size_t Capacity(){return capacity_;}void SetData(const uint8_t* data, size_t len){assert(len  capacity_);memcpy(data_, data, len);len_  len;}void SetLength(size_t len){assert(len  capacity_);len_  len;}
private:uint8_t* data_  nullptr;size_t    capacity_  0;size_t  len_  0;
};#endif #ifndef MEM_POOL_H_
#define MEM_POOL_H_
#include memory
#include vector
#include mutex
#include data_block.h
class MemPool
{
public:MemPool(size_t max_block_count);std::shared_ptrDataBlock Get(size_t capacity);
private:std::vectorstd::shared_ptrDataBlock pool_;std::mutex    mutex_;size_t max_block_count_;
};
#endif 
#include mem_pool.hMemPool::MemPool(size_t max_block_count): max_block_count_(max_block_count) {}
std::shared_ptrDataBlock MemPool::Get(size_t capacity)
{std::lock_guardstd::mutex guard(mutex_);int index  -1;for (size_t i  0; i  pool_.size(); i){if (pool_[i].use_count()  1  pool_[i]-Capacity()  capacity){if (index  -1){index  i;}else if (pool_[i]-Capacity()  pool_[index]-Capacity()){index  i;}}}if (index  -1){auto new_block  std::make_sharedDataBlock(capacity);if (pool_.size()  max_block_count_){pool_.push_back(new_block);}return new_block;}else{return pool_[index];}
} 
6C动态内存分配 C语言malloc()/free() C中new/delete 运算符 new运算符用于动态内存的分配delete运算符用于动态内存的释放。 C语言:       int *p  (int*)malloc(sizeof(int));       *p  100;       free(p); C:       int *p  new int(200);       //*p  200;       delete  p;        int* pa  new int[10];      pa[0]  10;      pa[1]  20;      ....      delete[] pa;