C++入门(三)之内存管理
目录
一、C/C++中程序内存分布
关于存储的问题
二、C语言中动态内存管理方式 ?
malloc/calloc/realloc和free
malloc
free?
calloc
?realloc
三、C++内存管理方式
new/delete操作内置类型
小问题:
对于自定义类型
关于调用自定义类型的实例
四、operator new与operator delete函数
对于开空间失败而言,C与C++不同之处
operator new
operator new与operator delete函数的底层实现(了解)
operator new与operator delete的类专属重载(了解)
内存池的概念:
五、new和delete的实现原理
内置类型
自定义类型
new的原理
delete的原理
new T[N]的原理
delete[]的原理
六、定位new表达式(placement-new) (了解)
使用格式:
使用场景:
七、常见面试题
malloc/free和new/delete的区别
八、内存泄漏
什么是内存泄漏
内存泄漏的危害
?代码体现
内存泄漏分类(了解)
如何避免内存泄漏 ?
九、如何一次在堆上申请4G的内存
一、C/C++中程序内存分布
ps: y以下内存是以32位程序下,linux系统讨论
这块叫进程虚拟地址空间(大约4G),每个程序都有这个空间,哪块要存数据,就要跟物理内存(电脑的实际内存)进行建立映射。平时在程序里看到的地址都是这块空间的地址,程序用那块,他就会建立那块的映射
栈,静态区,常量区,这块的空间的生命周期都是自动控制的
堆:程序运行过程中按需求,申请和释放空间,比如我们实现链表,数组栈等等,都是在堆开空间。堆这块空间的生命周期是手动控制的。
ps:栈可以通过函数_alloca进行动态分配,不过注意,所分配空间不能通过free或delete进行释放,堆无法静态分配,只能动态分配;
关于存储的问题
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{static int staticVar = 1;int localVar = 1;int num1[10] = { 1, 2, 3, 4 };int num2[] = { 1, 2, 3, 4 };char char2[] = "abcd";const char* pChar3 = "abcd";int* ptr1 = (int*)malloc(sizeof(int) * 4);int* ptr2 = (int*)calloc(4, sizeof(int));int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);free(ptr1);free(ptr3);
}
1. 选择题:
选项 : A . 栈 B . 堆 C . 数据段(静态区) D . 代码段(常量区)
(1)globalVar 在哪里? ____(2) staticGlobalVar 在哪里? ____
(3)staticVar 在哪里? ____(4) localVar 在哪里? ____
(5)num1 在哪里? ____
答案:C,C,C,A,A;
解析:globalVar是全局变量,在静态区;staticGlobalVar,staticVar都有static修饰,在静态区;localVar,num1 都是局部变量,在栈上。
(1)char2 在哪里? ____(2) * char2 在哪里? ___
(3)pChar3 在哪里? ____(4) * pChar3 在哪里? ____
(5)ptr1 在哪里? ____(6) * ptr1 在哪里? ____
答案:A,A,A,D,A,B
解析:
在栈帧上定义了pchar3,ptr1,他俩是指针, pchar3存的是“abcd”这块常量的地址。ptr1是在堆上开了块空间,存的是这块空间首元素的地址。char2在栈开了块空间,因为它是个数组,然后把“abcd”这块常量,拷贝到了空间中去。所以解引用char2还是在栈上,解引用pchar3就在常量区,解引用ptr1就在堆上。
ps:指针在全局定义的它就在静态区,在局部定义的就在栈上,看在哪定义。局部变量与类型是没有关系的。
2.填空题
(1)sizeof ( num1 ) = ____ ;(2) sizeof ( num2 ) = ____ ;
(3)sizeof ( char2 ) = ____ ; (4) strlen ( char2 ) = ____ ;
(5)sizeof ( pChar3 ) = ____ ;(6) strlen ( pChar3 ) = ____ ;
(7)sizeof ( ptr1 ) = ____ ;
答案:40,16,5,4,4/8,4,4/8
解析:num1 int类型开了10个空间,一共40个字节; num2 int类型开了4个空间;
char2,“abcd”,占空间但是不算长度,sizeof计算空间,strlen计算长度;
32位下指针4字节,64位下,指针8个字节
二、C****语言中动态内存管理方式
malloc/calloc/realloc和free
malloc
函数原型:void* malloc ( size_t size );
这个函数向内存申请一块 连续可用 的空间,并返回指向这块空间的指针。
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
- 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
free
函数原型:void free ( void* ptr );
free 函数用来释放动态开辟的内存。
- 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
- 如果参数 ptr 是NULL指针,则函数什么事都不做。
calloc
函数原型:void* calloc ( size_t num , size_t size );
- 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
- 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。
realloc
函数原型:void* realloc ( void* ptr , size_t size );
ptr 是要调整的内存地址
size 调整之后新大小
realloc函数的出现让动态内存管理更加灵活。
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存, 我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。
**三、C++**内存管理方式
C 语言内存管理方式在 C++ 中可以继续使用,但有些地方就无能为力而且使用起来比较麻烦,因此 C++ 又提出了自己的内存管理方式:通过 new 和 delete 操作符进行动态内存管理
new的用法:
delete的用法:
另外两种相匹配对应的:
new/delete****操作内置类型
动态申请int和5个int数组,
int main()
{//动态申请int和5个int数组 函数和关键字//总结 malloc/free 和 new/delete 对于内置类型来讲没有本质区别,只有用法上的区别int* p1 = (int*)malloc(sizeof(int));int* p2 = (int*)malloc(sizeof(int) * 5);int* p3 = new int;int* p4 = new int[5]; //动态申请5个int空间free(p1);free(p2);delete p3;delete[]p4;p1 = nullptr;p2 = nullptr;p3 = nullptr;p4 = nullptr;
}
malloc/free 和 new/delete 对于内置类型来讲没有本质区别,只有用法上的区别
但要注意的是:申请和释放单个元素的空间,使用new和delete操作符**,**申请和释放连续的空间,使用new[ ]和 delete[ ]
PS:C++98不支持初始化new的数组,但是C++11支持用{}初始化
int main() {//C++98不支持初始化new的数组,C++11支持用{}初始化int* p = new int[5]{ 1,2,3,4,5 }; }
小问题:
这两个有区别吗?
int main() {int* p1 = new int[5]; int* p2 = new int(5); }
答案是有的,第一个p1是动态申请5个int空间,第二个p2是动态申请一个int空间,并将这块空间初始化成5。
对于自定义类型
对于这样一个类A
class A
{
public:A(int a=0):_a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}private:int _a;
};
如果我们想要去申请自定义类型的空间时,我们可以使用malloc或者new,那么他俩有啥区别呢?
同样是动态申请单个A对象,和5个A对象数组
int main() {//动态申请单个A对象,和5个A对象数组A* p1 = (A*)malloc(sizeof(A));A* p2 = (A*)malloc(sizeof(A) * 5);//在堆上申请空间+调用构造函数初始化对象A* p3 = new A;A* p4 = new A[5]; }
通过执行结果监视我们发现malloc出来的啥都没干,new出来的调用了构造函数去初始化了对象,一共调用了6次构造函数。
同样对于free与delete
int main() {//动态申请单个A对象,和5个A对象数组A* p1 = (A*)malloc(sizeof(A));A* p2 = (A*)malloc(sizeof(A) * 5);//在堆上申请空间+调用构造函数初始化对象A* p3 = new A;A* p4 = new A[5];free(p1);free(p2);delete p3;delete[]p4; }
free就是释放掉了空间,delete除了释放空间,而且还调用了析构函数
还需要注意的是:malloc和free ,new和delete 要匹配使用,不要混合使用,否则可能会崩溃。
同样new 和delete 匹配 ,new[ ] 和delete [ ] 匹配
eg:
如果类中没有默认构造函数,申请空间时也会报错。
解决方法:
1.0 提供默认构造函数
2.0 单个用括号初始化,数组用{ }初始化
A* p3 = new A(100); A* p4 = new A[5]{1,2,3,4,5};
关于调用自定义类型的实例
对于这样一个栈类
class Stack
{
public:Stack(int capacity =4):_top(0),_capacity(capacity) {_a = new int[capacity];}~Stack(){delete[] _a;_top = _capacity = 0;}
private:int* _a;int _top;int _capacity;
};
int main()
{Stack st1; //st1在栈上//搞一个自己可以控制生明周期的Stack* pst2 = new Stack;//开空间+构造函数初始化//对象的指针delete pst2; //析构函数(清理对象中的资源)+释放空间return 0;
}
pst2指向动态开辟的空间,这个空间上有三个数据,一个指针,两个整形,紧接着Stack的构造函数又要开空间,开capacity个空间,第一个空间是给这个栈对象开空间,第二个空间是构造函数给这个栈对象里面的资源进行开空间。
delete pst2 第一步调用它的析构函数,清理调给_a开的空间,第二步释放掉栈对象本身的空间
总结下:new在堆上申请空间+调用构造函数初始化对象
delete先调用指针类型的析构函数+给堆上释放空间
C++提出new和delete,主要是解决两个问题
1.0自定义类型对象自动申请的时候,初始化和清理的问题。new和delete会调用构造函数和析构函数
2.0 new失败了以后要求抛异常,这样才符合面向对象语言的出错处理机制。
ps:delete和free一般不会失败,如果失败了,都是释放空间上存在越界或者释放指针位置不对。
四、operator new与operator delete****函数
对于开空间失败而言,C与C++不同之处
面向对象的语言,处理错误的方式一般是抛异常,C++中也要求出错抛异常–try catch
面向过程的语言,处理错误的方式是返回值+代码解决 (C语言)
C语言失败是将指针置空,C++是抛异常【异常必须被捕获,不捕获就会报错。C++用tyr与catch实现该操作】
C++捕获异常操作:结合try与catch使用,会输出 bad allocation
int main() {char* p1 = (char*)malloc(0x7fffffff); //2gif (p1 == nullptr){printf("malloc fail ");}try{char* p2 = new char[0x7fffffff];}catch (const exception&e){cout << e.what() << endl;}return 0; }
operator new
针对这个栈类实例
class Stack
{
public:Stack(int capacity =4):_top(0),_capacity(capacity) {_a = new int[capacity];}~Stack(){delete[] _a;_top = _capacity = 0;}
private:int* _a;int _top;int _capacity;
};
int main()
{Stack st1; //st1在栈上//搞一个自己可以控制生明周期的Stack* pst2 = new Stack;//开空间+构造函数初始化//对象的指针delete pst2; //析构函数(清理对象中的资源)+释放空间return 0;
}
我们通过反汇编观察new和delete的底层
通过反汇编我们发现给pst2开空间底层是调用了operator new这个函数
operator new 又是什么呢?
实际上它就是一个库函数,并不是new的重载,我们自己可以用它去开空间
它是不会去调用构造函数的
实际上它与malloc的用法是完全一样
这个函数并不是直接提供给用户用的,**实际上它是要对malloc的封装。**operator new中调用malloc申请内存,失败以后,改为抛异常处理错误,这样才符合C++面向对象语言处理错误的方式
如果说没有operator new ,在调用new(因为new是操作符)的时候,就会被转换成指令 call malloc +call 构造函数,调用构造函数一般而言不会失败,调用malloc假如失败,就返回0,那么new也是返回0,但是这样就不符合C++处理错误的方式,所以C++就增加了operator new ,专门给new 用。
可以简单理解为:
new=operator new +构造函数
operator new = malloc+抛异常
operator new与operator delete****函数的底层实现(了解)
new 和 delete 是用户进行 动态内存申请和释放的操作符 , operator new 和 operator delete 是系统提供的 全局函数 , new 在底层调用 operator new 全局函数来申请空间, delete 在底层通 operator delete 全局函数来释放空间。
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,
尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) {// try to allocate size bytesvoid *p;while ((p = malloc(size)) == 0)if (_callnewh(size) == 0){// report no memory// 如果申请内存失败了,这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData) {_CrtMemBlockHeader * pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK); /* block other threads */__TRY/* get a pointer to memory block header */pHead = pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg( pUserData, pHead->nBlockUse );__FINALLY_munlock(_HEAP_LOCK); /* release other threads */__END_TRY_FINALLYreturn; }
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
通过上述两个全局函数的实现知道, operator new 实际也是通过 malloc 来申请空间 ,如果 malloc 申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过 free 来释放空间的。
operator new与operator delete****的类专属重载(了解)
针对这个list讲解
struct ListNode
{ListNode* _next;ListNode* _prev;int _data;ListNode(int val):_next(nullptr), _prev(nullptr), _data(val){}void* operator new(size_t n) //这时候我就不在malloc申请{void* p = nullptr;p = allocator<ListNode>().allocate(1); //stl中的内存池--空间配置器cout << "memory pool allocate" << endl;return p;}void operator delete(void* p){allocator<ListNode>().deallocate((ListNode*)p, 1);cout << "memory pool deallocate" << endl;}
};
class List
{
public:List(){_head = new ListNode(-1);_head->_next = _head;_head->_prev = _head;}void PushBack(int val){ListNode* newnode = new ListNode(val); //这调用的是全局的operator newListNode* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;}~List(){ListNode* cur = _head->_next;while (cur != _head){ListNode* next = cur->_next;delete cur;cur = next;}delete _head;_head = nullptr;}
private:ListNode* _head;
};
int main()
{List l;l.PushBack(1);l.PushBack(2);l.PushBack(3);l.PushBack(4);l.PushBack(5);return 0;
}
给了一个list,使用的时候会用很多的节点,都是小块小块的内存,频繁的去找系统要内存效率可能会比较低,能不能让它动态申请内存的时候不要去找系统要,而是找内存池去申请内存,进而提高效率呢?
内存池的概念:
内存池是啥?
比如说有一家人在山上住着,山顶上没有水,只有山下有一条河,想用水的时候该怎么办呢?
第一种方式就是:用的时候才去山下打水,比如要喝水,去山下喝了水以后,又回到了山上,每次用水的时候都下山去打水回来,用一点拿一点。
[平时我们使用就类似第一种方式:操作系统的堆就像这条小河,链表要插入数据就需要一个节点,就需要去找一下堆,频繁去找堆,效率就是低的。]
第二种方法就是,在山上建一个水池,提前在这个水池里储备好水,用的时候,让水池里放点水出来,这样就比第一种高效。
[内存池就类似第二种方式,不要去频繁的找堆,提前把内存储备起来,找堆,一次性申请很多,把它们放到内存池中,效率就高很多了,这种技术就叫做池化技术] .
这两个就是我们在Listnode里实现的专属operator new 与operator delete,这样的话使用new就不会去调用全局的operator new(系统库里面的),而是调用我们自己写好的,实现链表节点使用内存池申请和释放内存,提高效率
void* operator new(size_t n) //这时候我就不在malloc申请{void* p = nullptr;p = allocator<ListNode>().allocate(1); //stl中的内存池--空间配置器cout << "memory pool allocate" << endl;return p;}void operator delete(void* p){allocator<ListNode>().deallocate((ListNode*)p, 1);cout << "memory pool deallocate" << endl;}
通过运行结果显示,确实调用了专属的operator new 与operator delete
五、new和delete****的实现原理
内置类型
- 如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。
自定义类型
new****的原理
- 调用operator new函数申请空间
- 在申请的空间上执行构造函数,完成对象的构造
delete****的原理
- 在空间上执行析构函数,完成对象中资源的清理工作
- 调用operator delete函数释放对象的空间
**new T[N]**的原理
- 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
- 在申请的空间上执行N次构造函数
**delete[]**的原理
- 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
- 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
实际上newT[N] 与delete [ ] 就是对 operator new与operator delete的封装
六、定位new表达式**(placement-new)** (了解)
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
new (place_address) type 或者 new (place_address) type(initializer-list)
place_address 必须是一个指针, initializer-list 是类型的初始化列表
使用场景:
定位 new 表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new 的定义表达式进行显示调构造函数进行初始化。
eg:对这样的一个类
class Test
{
public:Test(int data=0): _data(data){cout << "Test():" << this << endl;}~Test(){cout << "~Test():" << this << endl;}private:int _data;
};
int main()
{Test* p = (Test*)malloc(sizeof(Test));new(p)Test(1);//new(p)Test;Test* p2 = new Test(2);delete p2;//等价于Test* p3 = (Test*)operator new(sizeof(Test));new(p3)Test(3);p3->~Test();operator delete(p3);
}
malloc出来的不会调用构造函数,用定位new去初始化malloc出来的p;
ps: p 现在指向的只不过是与 Test 对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
这种是初始化成自己想要的值。
同理对operator new也一样可以使用
七、常见面试题
malloc/free和new/delete****的区别
malloc/free 和 new/delete 的 共同点 是:都是从堆上申请空间,并且需要用户手动释放。
不同的 地方是:
- 1. malloc和free是函数,new和delete是操作符
- 2. malloc申请的空间不会初始化,new可以初始化
- 3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
- 4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
- 5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
- 6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间 后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
八、内存泄漏
什么是内存泄漏
什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
通俗一点来讲就是:动态申请的内存,不使用了,又没有主动去释放他,就存在内存泄漏
内存泄漏的危害
**进程的工作原理:**我们启动一个程序,开始我们的任务,然后等任务结束了,我们就停止这个进程。 进程停止后, 该进程就会从进程表中移除。
僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源
- 出现内存泄漏的进程正常结束,进程结束时这些内存会还给系统,不会有太大的危害
- 出现内存泄露的进程非正常结束,比如僵尸进程,危害很大,系统会越来越慢,甚至卡死宕机
- 需要长期运行的程序,出现内存泄漏,危害很大,系统会越来越慢,甚至卡死宕机–服务器程序,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死
代码体现
void MemoryLeaks(){// 1.内存申请了忘记释放int* p1 = (int*)malloc(sizeof(int));int* p2 = new int;// 2.异常安全问题int* p3 = new int[10];Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.delete[] p3;}
内存泄漏分类(了解)
C/C++ 程序中一般我们关心两种方面的内存泄漏:
- 堆内存泄漏**(Heap leak)**
- 堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
- 系统资源泄漏
- 指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
如何避免内存泄漏
- 1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:这个理想状
- 态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保
- 证。
- 2. 采用RAII思想或者智能指针来管理资源。
- 3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
- 4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。
总结一下:
内存泄漏非常常见,解决方案分为两种: 1 、事前预防型。如智能指针等。 2 、事后查错型。如泄漏检测工具。
九、如何一次在堆上申请4G的内存
首先改为64位
int main() {void* p = new char[0xfffffffful];cout << "new:" << p << endl;cout << sizeof(p) << endl;return 0;}
申请成功
32位下,是不能超过2g的
C++入门(三)之内存管理相关推荐
- 操作系统第三章-内存管理
写在前面:本文参考王道论坛的 操作系统考研复习指导单科书 下面的流程图很重要. 加入快表的基本分页 加入快表的二级页表!! 虚拟存储器:请求分页的流程图. 文章目录 第三章 内存管理 3.1 内存管理 ...
- 操作系统:第三章 内存管理2 - 详解虚拟内存,页面置换算法,页面分配策略
本文已收录至 Github(MD-Notes),若博客中有图片打不开,可以来我的 Github 仓库:https://github.com/HanquanHq/MD-Notes,涵盖了互联网大厂面试必 ...
- 操作系统(三)内存管理
操作系统(三)内存管理 一.程序执行过程 装入的三种方式 链接的三种方式 二.内存管理的概念 内存空间的分配与回收 连续分配管理方式 单一连续分配 固定分区分配 动态分区分配 首次适应算法 最佳适应算 ...
- (王道408考研操作系统)第三章内存管理-第二节3:页面置换算法2
上接: (王道408考研操作系统)第三章内存管理-第二节2:页面置换算法1 文章目录 一:时钟置换算法(CLOCK) (1)简单时钟置换算法 (2)改进型时钟置换算法 二:页面置换算法总结 一:时钟置 ...
- (王道408考研操作系统)第三章内存管理-第二节1:虚拟内存管理基本概念
文章目录 一:传统存储管理方式的弊端 二:局部性原理与高速缓冲技术Cache (1)Cache基本原理 (2)局部性原理 三:虚拟内存的定义和特征 (1)定义 (2)特征 四:虚拟内存实现 内存管理需 ...
- C++大法:举世闻名之BOOST大法精华浅析(三)内存管理库(小白piao分享)
文章目录 三.内存管理库 3.1 smart_ptr 3.1.1 RAII机制 3.1.2 智能指针 3.1.3 scoped_ptr 3.1.4 scoped_array 3.1.5 shared_ ...
- Pascal游戏开发入门(三):游戏对象管理
Pascal游戏开发入门(三):游戏对象管理 游戏中有很多类对象,例如:角色,敌人,NPC,陷阱,子弹,门等等.跟踪并处理它们之间的交互是一个有难度的事情.为了尽可能简化并使之容易维护,本节将尝试使用 ...
- Objective-C入门解读与内存管理方式
Objective-C入门 Objective-C入门(A First Look at Objective-C) 转自: http://www.fish888.com/Objective-C-t684 ...
- 现代操作系统:第三章 内存管理
操作系统的工作是将这个存储体系抽象成为一个有用的模型并将管理这个抽象模型 操作系统中管理分层存储体系的部分称为存储管理器.它的任务是有效的管理内存,即记录哪些内存是正在使用的,哪些内存是空闲的,在进程 ...
- 操作系统【三】内存管理基础+连续内存分配
内存的基础知识 内存分为按字节编址(8位)和字编制(不同计算机不一样,64位计算机就是64位,即8个字节) 相对地址=逻辑地址 绝对地址=物理地址 从逻辑地址到物理地址的转换由装入解决. 装入的三种方 ...
最新文章
- 面试官问:ZooKeeper 一致性协议 ZAB 原理
- 函数式编程学习之路(三)
- ​CSRankings年度更新,清华北大包揽AI领域前两名​ | AI日报
- 烂泥:nginx同时支持asp.net与php
- MyBatis学习总结(三)——优化MyBatis配置文件中的配置
- 射频全网通笔记(附全球频段划分及主要运营商对应表)
- megacli通过盘符定位物理盘_柴少鹏的官方网站
- 第七章:跨程序共享数据-探究内容提供器
- compilation error错误是什么原因_了解如何使用Try,Throw,Catch和Last处理JavaScript错误...
- UI设计灵感|996打工人必备,日程计划网页设计
- Node接口也定义了一些所有节点类型都包含的特性和方法
- 设置linux环境变量
- 算法面试题 java_【面试算法题】Java Stack 类的使用
- 【Cocos2d-html5】运动中速度效果
- 专用集成电路设计实用教程(学习笔记一)
- 游戏直播用哪个录屏软件好?
- sql 树形 子节点获取最顶级的节点
- 数智化升级:红蜻蜓的转型之路(上)
- 大脑神经网络图高清,图神经网络 图像
- c++头文件iomanip.h中的setw、setprecision、setfill和setbase函数
热门文章
- 英语学习果然是要靠坚持
- 从德国勒索软件活动看恶意代码的生存方式-云栖社区-阿里云
- 如何用matlab绘制双调谐滤波器的阻抗频率特性曲线,一种双调谐无源滤波器的参数设计方法与流程...
- freemarker模板导出word循环图片表格详细教程
- 解决 https 无法访问
- 根据中国古诗词作画,AI 可以做到吗?
- Reptile:requests + BeautifulSopu 实现古诗词网三国名著下载
- Python_真值表求解器(逻辑表达式的求解)(eval实现求解)【2022-01-22】
- GPS导航系统的基本原理
- 联想和戴尔的渠道之争