HTML隐藏高性能得到隐
HTML在C/隐藏中,内存管理是一个非常困难的问题。当我们编写程序时,几乎不可避免地遇到内存的分布逻辑。在此时间,可用于分配吗?如果分销失败,该怎么办?如何管理自己的内存使用情况?
I.概述
在C/隐藏中,内存管理是一个非常困难的问题。当我们编写程序时,我们几乎不可避免地会遇到内存分布的逻辑。在此timememory可以分配?如果分销失败,该怎么办?如何管理自己的内存使用情况?和其他一系列问题。在高度可用的软件中,如果我们只是将内存申请到操作系统,则在不足的内存时退出软件显然是不合理的。正确的想法应该考虑如何管理和优化该软件它已经使用过的内存,以使软件更可用。在此项目中,我们将实现隐藏的并使用堆栈结构来测试我们隐藏的分布性能。
最后,我们想实现的堆栈结构中隐藏的性能
项目涉及的知识点
HTML STD ::分配器中的内存分配器
隐藏的技术
手动实现模板隐藏
隐藏和HTML性能比较
介绍
隐藏是合并技术的一种形式。通常,我们使用新删除的关键字在编写程序时将内存申请到操作系统。分配内存的需求。如果此操作过于频繁,它将找到大量内存片段以降低内存的分布性能,甚至失败了内存分布的失败。隐藏的是一种解决此问题的技术。从内存分布的概念,内存应用程序不过是要求指向记忆的指针分配。在将内存申请到操作系统时,操作系统需要执行复杂的内存管理计划,然后才能正确分配相应的指针。在此分布的过程中,我们还面临未能分配的风险。每次执行内存分布时,一次分配内存的时间将一次消耗。让我们将这次设置为T。然后,NT总消费的总消费将为NT;如果我们确定可能需要多少内存,那么它就在其中,然后在其中,然后在其中,然后在其中,以便在其中。记忆区域。当我们需要内存时,请直接从已分配的内存中使用它,因此所需的总分布时间仅为T。当N更大时,节省的时间就越多。
第二,主要功能设计
我们想设计一个高性能的隐藏,因此自然无法避免比较现有内存的需要,并比较隐藏的内存分布性能,我们需要实现一个需要动态分配给内存的结构。
(例如:隐藏),为此,您可以编写以下代码:
#隐
#隐
#隐
#隐
#hidden“ MemoryPool.hpp” // MemoryPool
#hidden“ stackalloc.hpp” // Stackalloc
//插入元素
#Define Elems 10000000
//重复时间
#Define Reps 100
int main()
{{
clock_t start;
//使用STL默认配电程序
Stackalloc
start = clock();
for(int j = 0; j 断言(stackDefault.empty()); for(int i = 0; i stackdefault.push(i); for(int i = 0; i stackDefault.pop(); } std :: cout<< "Default Allocator Time:";;;; std :: cout<< ((DOUBLE) CLOCK () -Start) / CLOCKS_PER_SEC) << \ n \ n "; //使用隐藏 Stackalloc start = clock(); for(int j = 0; j 断言(stackpool.empty()); for(int i = 0; i stackpool.push(i); for(int i = 0; i stackpool.pop(); } std :: cout<< "MemoryPool Allocator Time:";;;; std :: cout<< ((DOUBLE) CLOCK () -Start) / CLOCKS_PER_SEC) << \ n \ n "; 返回0; } 在段代码中,Stackalloc是一个隐藏的,接受两个模板参数。第一个参数是堆栈中的元素类型,第二个参数是堆栈使用的内存分配。 因此,此内存分配的模板参数是整个比较过程中唯一的变量。使用默认配电设备的模板参数为std ::分配器用于使用内存使用内存 池的模板参数是MemoryPool。 STD ::分配器是HTML标准库中提供的默认分布。他的特征是,当我们使用新对象申请新对象以申请内存构造时,我们必须称呼类对象的默认构造函数,而使用std ::分配器是内存分配的两个部分,并且可以是对象的结构分开,使得分布式内存是原始的和非结构化的。 让我们隐藏起来。 3.隐藏模板 堆栈的结构非常简单。没有复杂的逻辑操作。成员函数只需要考虑两个基本操作:输入堆栈,从堆栈中。在操作方便中,我们也可能仍然 有必要确定堆栈是否为空,清除堆栈并获得堆栈的顶部元素。 #隐 模板 start stacknode_ {{ t数据; stacknode_* prev; }; // T是存储对象的类型,Alloc是使用的分配器,默认情况下将STD ::分配器用作对象 模板 类stackalloc {{ 民众: //使用Typedef简化类型名称 typedef stacknode_ typedef typename alloc ::模板重新启动 //默认结构 stackalloc(){head_ = 0;} //默认结构 〜stackaloc(){clear();} //当堆栈中的元素为空时返回true bool empty(){return(head_ == 0);} //在堆栈中释放元素的所有内存 void clear(); //按堆栈 void推动(t元素); //堆栈 t pop(); //返回堆栈的顶部元素 t top(){return(head _-> data);} 私人的: // 分配分配器_; //顶部 节点* head_; }; 简单的逻辑,例如结构,破坏,判断堆栈的逻辑,并返回堆栈的顶部元素,非常简单。它是在上述定义中直接实现的。 POP()的三个重要逻辑: //在堆栈中释放元素的所有内存 void clear(){ 节点* curr = head_; //按顺序排出堆栈 while(curr!= 0) {{ 节点* tmp = curr-> prev; //首先结构,然后回收内存 分配者_.destroy(Curr); allcator_.deallocate(Curr,1); curr = tmp; } head_ = 0; } //输入堆栈 void push(t元素){ //为节点分配内存 节点* newnode = allocator_.allocate(1); //调用节点的构造函数 allcator_.construct(newnode,node()); //输入堆栈操作 newnode-> data = element; newnode-> prev = head_; head_ = newnode; } //堆栈 t pop(){{ //退出堆栈操作,返回堆栈元素 t结果=头_->数据; 节点* tmp = head _-> prev; 分配器_.destroy(head_); altocator_.deallocate(head_,1); head_ = tmp; 返回结果; } 在这一点上,我们已经完成了整个模板。现在,我们可以对Main()函数中的Main()函数进行评论,以测试缠绕堆栈的内存分布。 我们可以得到这样的结果: 在默认的std ::分配器的内存分配中 #Define Elems 10000000 #Define Reps 100 在这种情况下,总共花费了将近一分钟的时间。 如果您认为这需要很长时间并且不想等待,则可以尝试降低这两个值 总结; 在本节中,我们实施了一个隐藏的模板,以进行测试性能比较。当前的代码如下。在下一部分中,我们开始详细介绍自己的高性能。 // stackalloc.hpp #ifndef stack_alloc_h #define stack_alloc_h #隐 模板 start stacknode_ {{ t数据; stacknode_* prev; }; // T是存储对象的类型,Alloc是使用的分销商, //使用std ::分配器作为对象的分配器的对象 模板 类stackalloc {{ 民众: //使用Typedef简化类型名称 typedef stacknode_ typedef typename alloc ::模板重新启动 //默认结构 stackalloc(){head_ = 0;} //默认结构 〜stackaloc(){clear();} //当堆栈中的元素为空时返回true bool empty(){return(head_ == 0);} //在堆栈中释放元素的所有内存 void clear(){ 节点* curr = head_; while(curr!= 0) {{ 节点* tmp = curr-> prev; 分配者_.destroy(Curr); allcator_.deallocate(Curr,1); curr = tmp; } head_ = 0; } //输入堆栈 void push(t元素){ //为节点分配内存 节点* newnode = allocator_.allocate(1); //调用节点的构造函数 allcator_.construct(newnode,node()); //输入堆栈操作 newnode-> data = element; newnode-> prev = head_; head_ = newnode; } //堆栈 t pop(){{ //退出堆栈操作并返回堆栈结果 t结果=头_->数据; 节点* tmp = head _-> prev; 分配器_.destroy(head_); altocator_.deallocate(head_,1); head_ = tmp; 返回结果; } //返回堆栈的顶部元素 t top(){return(head _-> data);} 私人的: 分配分配器_; 节点* head_; }; #endif // stack_alloc_h // main.cpp // #hidden“ memorypool.hpp” #hidden“ stackalloc.hpp” //根据计算机性能调整这些值 //插入元素 #Define Elems 25000000 //重复时间 #Define代表50 int main() {{ clock_t start; //使用默认配电设备 Stackalloc start = clock(); for(int j = 0; j 断言(stackDefault.empty()); for(int i = 0; i stackdefault.push(i); for(int i = 0; i stackDefault.pop(); } std :: cout<< "Default Allocator Time:";;;; std :: cout<< ((DOUBLE) CLOCK () -Start) / CLOCKS_PER_SEC) << \ n \ n "; //使用隐藏 // Stackalloc // start = clock(); // for(int j = 0; j //断言(stackpool.empty()); // for(int i = 0; i // stackpool.push(i); // for(int i = 0; i // stackpool.pop(); //} // std :: cout<< "MemoryPool AloCator Time:";;;;; // std :: cout<< ((DOUBL) CLOCK () - Start) / CLOCKS_PER_SEC) << \ n \ n "; 返回0; } 第二,设计隐藏 在上一节的实验中,我们使用了隐藏模板中的默认构造函数来管理堆栈操作中的元素内存,涉及总共recind ::其他,分配,dealocate(),dealocate(),construct(),construct(),销毁()键接口。因此,为了直接使用代码,我们还应在隐藏中设计相同的接口: #IFNDEF MOMENE_POOL_HPP #Define Memory_pool_hpp #隐 #隐 模板 类MemoryPool {{ 民众: //使用Typedef简化类型写作 Typedef t*指针; //定义重建::其他界面 模板 Typedef MemoryPool其他; }; //默认结构,初始化所有凹槽指针 // html 11使用noexcept明确声明此功能不会引发异常 memoryPool()noexcept { CurrentBlock_ = nullptr; currentlot_ = nullptr; lastSlot_ = nullptr; freeSlots_ = nullptr; } //销毁现有的隐藏 〜MemoryPool()noexcept; //同时,只能分配一个对象,n和提示将被忽略 指针分配(size_t n = 1,const t* shint = 0); //指针P点存储器块的破坏 void DeadLocate(指针P,size_t n = 1); //致电构造函数 模板 void constic(u* p,args && ... args); //在隐藏中销毁物体,即 模板 void destroy(u* p){ p-> 〜u(); } 私人的: //用于将对象插槽存储在隐藏中, //它要么瞬时成一个存储对象的插槽, //要么瞬时地插入针对目标插槽的插槽指针 联合插槽_ { t元素; slot_* next; }; //数据指针 typedef char* data_pointer_; //对象插槽 typedef slot_slot_type_; //对象凹槽指针 typedef slot_* slot_pointer_; //指向当前内存块 slot_pointer_currentblock_; // pind到当前内存块的对象插槽 slot_pointer_currentslot_; // pind到当前内存块的最后一个对象插槽 slot_pointer_ lastslot_; // pind到当前内存块中的空闲对象插槽 slot_pointer_ freeslots_; //检查隐藏大小的大小是否太小 static_assert(blocksize> = 2 * sizeof(slot_type_),“ blocksize too Smart。”); }; #endif // memory_pool_hpp 在上面的设计中,可以看出,在此隐藏中,链接列表实际上用于管理整个隐藏的内存块。隐藏首先定义了基本内存块(块),然后定义了对象组合的组合可以实例化到对象凹槽(slot_)和对象插槽指针的凹槽(slot_)。在块中,定义了四个关键属性。他们的功能是: CurrentBlock_:指向当前内存块的诗 CurrentsLot_:当前内存块中对象插槽的指示 LastSlot_:当前内存块的最后一个对象插槽 freeSlots_:指向当前内存块中的所有空闲对象插槽 在整理整个隐藏的设计结构之后,我们可以开始实现关键逻辑。 三,实施 MemoryPool ::构造()实现 MemoryPool :: construction()的逻辑是最简单的。我们需要实现的只是调用字母对象的构造函数,因此: //致电构造函数,使用std ::向前 模板 void constic(u* p,args && ... args){ 新(p)u(std ::前锋 } MemoryPool :: DealLocate()实现 MemoryPool :: DealLocate()是在对象插槽中的对象被破坏后调用的。主要目的是破坏内存插槽。它的逻辑并不复杂: //指针P点存储器块的破坏 void Deallocate(指针P,size_t n = 1){{{ 如果(p!= nullptr){ // reinterpret_cast是强制性类型的转换符号 //要接下来,您必须将P转换为slot_pointer_ reinterpret_cast freeSlots_ = reinterpret_cast } } MemoryPool :: 〜MemoryPool()实现 破坏性功能负责破坏整个隐藏,因此我们需要逐一删除操作系统的初始应用的内存块: //销毁现有的隐藏 〜MemoryPool()noexcept { //破坏在隐藏中分配的内存块 slot_pointer_curr = CurrentBlock_; while(curr!= nullptr){ slot_pointer_ prev = curr-> next; 操作员删除(reinterpret_cast curr = prev; } } memorypool ::分配()实现 MemoryPool ::分配()无疑是整个隐藏的关键,但实际上,在阐明了整个隐藏的设计后,实现并不复杂。具体的实现如下: //同时,只能分配一个对象,n和提示将被忽略 指针分配(size_t n = 1,const t* hint = 0){{{ //如果有空闲对象插槽,请直接传递免费区域 if(freeslots_!= nullptr){ 指针结果= reinterpret_cast freeSlots_ = freeSlots _-> next; 返回结果; } 别的 {
发表评论