顺德定制网站建设/网络培训网站
目录
- 内存布局思维导图
- 1.C/C++内存分布
- 数据段:
- 栈:
- 代码段:
- 堆:
- 2.C语言中动态内存管理方式
- 3.C++内存管理方式
- 3.1new/delete操作内置类型
- 3.2new和delete操作自定义类型
- 4.operator new 与 operator delete函数
- 5.new和delete的实现原理
- 5.1内置类型
- 5.2自定义类型
- 6.必须匹配的操作符
- 6.1内置类型
- 6.2自定义类型
- new -- free
- new[]--free/new[]--delete
- 7.定位new表达式
- 7.1使用格式:
- 7.2使用场景:
- 7.3内存池
- 8.面试题
- malloc/free和new/delete的区别
- 9.总结和博客思维导图
内存布局思维导图
- 上图为内存布局的思维导图,有关整篇博客的思维导图放在的最后的总结部分
1.C/C++内存分布
我们对比图片观察不同的数据存放在那个内存空间的那一块(对C语言内存管理不熟悉可查看该篇博客:【C语言】内存管理):
- 栈: 又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的。
- 内存映射段: 是高效的
I / O映射方式
,用于装载一个共享的动态内存库。用户可使用系统接口创建共享的共享内存,做进程通信。 - 堆: 用于程序运行时动态内存分配,堆是可以上增长的。
- 数据段: 存储全局数据和静态数据。
- 代码段: 可执行的代码/只读常量
接着我们对上图的代码分布情况做出如下解释(上图的代码放在解释后,有需要的可以自己复制运行一下)
数据段:
全局变量,static修饰创建的静态变量一定存放在数据段,存放静态数据和全局数据的地方,这个没有异议。
栈:
localNum变量,num1数组 正常在栈上开的空间创建,也很好理解。
至于char2、pChar3、ptr1、ptr2和ptr3 ,我们需要明白一点,不论是数组还是指针,不论接收的是常量字符串还是程序员自己开辟的空间的地址,它们终究是在函数内,是在栈上创建的变量,用来存放数据罢了,它们作为变量的地址就在栈上。
代码段:
在C语言中我们就应该知道,使用双引号括起来的数据为常量字符串,这样的字符串为只读常量,不能修改,存放在代码段(常量区),这是规定好的,我们理解记忆即可,但其中有一些比较迷惑人的地方需要解释一下:
-
使用数组和指针的形式接收常量字符串结果是不同的。
使用数组接收: 如上图的
char char2[]="abcd";
,常量字符串存放在代码段,在赋值时,char2在栈上开辟一个相同大小的数组,通过拷贝将每个字符存放在数组中(包含最后的’\0’终止字符),所以我们可以修改数组char2中的数据。使用指针接收:
-
C++: 如上图的
const char* pChar3 = "abcd";
,这个就要好理解了,就是简单的将常量字符串的首地址存入指针变量pChar而已,所以pChar3的地址是在栈上,而指针变量pChar3所存的地址是在代码段中。因为常量字符串不能修改,所以在C++中不允许权限发生改变,必须使用const关键字修饰指针。 -
C: 在C语言中,使用指针接收字符串常量则可以不使用const修饰指针,甚至我们可以使用指针来修改常量字符串编译器不会报错,但这样的程序是运行不了的,程序在执行到常量字符串修改哪一行就会停下(如下图),所以我们用C语言遇到这种情况最好还是使用const修饰。
-
堆:
程序员使用malloc、calloc、realloc 开辟的空间必然是放在堆上的,这样的空间,程序员自己申请也需要自己使用free 释放。空间在堆上开辟好后,分别使用指针接收这些空间的首地址,所以接收这些地址的指针变量是在栈上开辟,但它们所存储的地址却是在堆上。
代码如下:
int globalNum = 1;
static int staticGlobalNum = 1;int main()
{static int staticNum = 1;int localNum = 1;int num1[10] = { 1,2,3,4 };char char2[] = "abcd";const char* pChar3 = "abcd";int* ptr1 = (int*)malloc(sizeof(int));int* ptr2 = (int*)calloc(4, sizeof(int));int* ptr3 = (int*)realloc(ptr2,sizeof(int) * 4);free(ptr1);free(ptr3);return 0;
}
2.C语言中动态内存管理方式
C语言动态开辟内存的方式即为malloc、calloc和realloc,最后由free释放开辟的空间,这是学习C必须要掌握的对象,而面试时也会经常问道相关的问题,我们通过下面两道面试题在来看一下
1.malloc/calloc/realloc的区别?
- malloc向堆区申请空间,参数为申请内存的大小
- calloc向堆区申请空间,第一个参数为申请空间的每一个字节的初始值,第二个参数为申请空间的大小
- realloc向堆区申请空间,第一个参数为要调整的地址,第二个参数为调整后新的空间的大小,若第一个参数为空,则realloc和malloc相同。
- 向堆申请的空间必须使用free释放,防止内存泄漏。
2.malloc的实现原理
- GLibc堆利用入门-机制介绍
(比较复杂,建议结合操作系统一起学习)
3.C++内存管理方式
C语言管理内存的方法(malloc、calloc、realloc、free)在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,比如说自定义类型,因此C++提出了自己的内存管理方式:通过new和delete操作符进行内存管理。
3.1new/delete操作内置类型
我们以int
类型为类
-
动态申请一个int类型的空间
int* ptr1 = new int;//申请空间 delete ptr1;//释放空间
直接new后跟类型即可向堆申请空间。
-
动态申请一个int类型的空间并初始化为8
int* ptr2 = new int(10);//申请空间 delete ptr2;//释放空间
在类型后加小括号,在其内填写需要初始的值
- 若小括号内不添加任何值,默认初始化为0
-
动态申请10个int类型的空间
int* ptr3 = new int[10];//申请空间 delete[] ptr3;//释放空间
在类型后加中括号,其内填需要申请的同类型空间的个数
-
动态申请10个int连续的空间并初始化
在中括号后加小括号,在其内不添加任何值,默认初始化为0
int* ptr4_1 = new int[10]();//申请空间 delete[] ptr4_1;//释放空间
在中括号后加大括号,在其内填写数组的值,不足的部分默认为0
int* ptr4_2 = new int[10] {1,2,3,4};//申请空间 delete[] ptr4_2;//释放空间
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],需要匹配起来使用,不能乱用。(原因请看 6.必须匹配的操作符 )
通过下面代码查看,创建空间是否成功
int main()
{int* ptr1 = new int;int* ptr2_1 = new int(10);int* ptr2_2 = new int();int* ptr3 = new int[4];int* ptr4_1 = new int[4]();int* ptr4_2 = new int[4]{ 1,2 };printf("ptr1:%p %d\n", ptr1, *ptr1);printf("ptr2_1:%p %d\n", ptr2_1,*ptr2_1);printf("ptr2_2:%p %d\n", ptr2_2, *ptr2_2);for (int i = 0; i < 4; i++){printf("ptr3:%p %d\n", &ptr3[i], ptr3[i]);}for (int i = 0; i < 4; i++){printf("ptr4_1:%p %d\n", &ptr4_1[i], ptr4_1[i]);}for (int i = 0; i < 4; i++){printf("ptr4_2:%p %d\n", &ptr4_2[i], ptr4_2[i]);}delete[] ptr4_1;delete[] ptr4_2;delete[] ptr3;delete ptr2_1;delete ptr2_2;delete ptr1;return 0;
}
3.2new和delete操作自定义类型
new 和 delete操作自定义类型和操作内置类型相同。
new/delete 和malloc/free对于自定义类型时,不同的是申请空间时:new会调用构造函数,释放空间时:delete会调用析构函数
class A
{
public:A(int a = 0){_a = a;cout << "A(int a = 0)" << " " << _a << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};int main()
{A* ptr1 = new A(1);delete ptr1;A* ptr2 = new A;delete ptr2;A* ptr3 = new A[4];//调用四次构造函数delete[] ptr3;//释放四次构造函数A* ptr4 = new A[4]{ 1,2,3,4 };//为每次调用的构造函数传值delete[] ptr4;return 0;
}
对于malloc和free,什么都不会调用
class A
{
public:A(int a = 0){_a = a;cout << "A(int a = 0)" << " " << _a << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};int main()
{A* ptr1 = (A*)malloc(sizeof(A));if (ptr1 == nullptr){perror("malloc fail!");exit(-1);}free(ptr1);A* ptr2 = (A*)malloc(sizeof(A)*4);if (ptr1 == nullptr){perror("malloc fail!");exit(-1);}free(ptr2);return 0;
}
优势:
- 更简洁
- 申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc它们三个不会
- new申请空间失败会抛出异常,而malloc需要自己判断是否申请成功(一些严格的编译器必须要判断)
4.operator new 与 operator delete函数
new和delete 是用户进行动态内存申请和释放的操作符,operator new 和 operator delete 是系统提供的全局函数
- new在底层调用operator new 全局函数来申请空间
- delete在底层通过operator delete 全局函数来释放空间。
我们编写如下代码,通过汇编查看
class A
{
public:A(int a = 0){_a = a;cout << "A(int a = 0)" << " " << _a << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};int main()
{A* ptr = new A;delete ptr;return 0;
}
- 根据这些我们知道,new在申请空间时是通过operator new 申请,之后调用构造函数初始化。
至于delete我使用的VS2019不方便查看,大家要明白它底层调用的是operator delete ,还有下面的一点。
- 注意:对于自定义类型的对象,一定是先调用析构函数,清理掉对象的数据,之后再使用operator delete 释放空间,否则空间之间释放,析构函数就没办法调用了。(内置类型没有这个需求,直接释放)
接着我们看一下operator new 和 operator delete 是则么实现的:
operator new:
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);
}
- 观察第5行,operator new 实际上是通过malloc 来申请空间
- 当malloc 申请空间成功时直接返回;
- 当申请失败,且用户设置了空间不足应当措施,则尝试执行该措施,继续申请。若没有设置,则抛出异常。
operator delete:
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)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;
}
- 观察第4行和18行,operator delete 实际上是通过free 释放空间的
我们可以将operator new 和 operator delete 看作是对malloc和free 的封装,之所以要这么做是因为C++是面向对象的语言,当申请空间发生错误时不能像C那样去处理问题,直接返回个NULL,需要让用户更直观的看到问题的出现,需要增加异常 这个功能,如果了解一些Java的知识,想必对异常并不陌生,这正是面向对象的特点。
5.new和delete的实现原理
5.1内置类型
申请内置类型的空间,new和malloc,delete和free基本类似, 不同的地方有以下两点:
- new/delete申请和释放单个元素的空间,new[]/delete[]申请和释放的是连续的空间,malloc和free不用区分这些
- new再申请空间失败时会抛出异常,malloc会返回NULL
5.2自定义类型
-
new的原理
- 调用operator new函数 申请空间
- 在申请的空间上执行构造函数,完成对象的构造
-
delete的原理
- 在空间上执行析构函数,完成对象中资源的清理工作。
- 调用operator delete函数 释放对象的空间
-
new T[N]的原理
-
调用operator new[]函数 申请空间
operator new[] 中实际调用operator new函数完成N个对象的申请。
-
在申请的空间上执行N次构造函数
-
-
delete[]的原理
-
在释放的对象空间上执行N次析构函数,完成N个对象资源的清理
-
调用operator delete[] 释放空间
与operator new[]相同,operator delete[]中调用operator delete来释放空间。
-
6.必须匹配的操作符
我们使用操作符申请空间时,必须匹配使用,malloc/free、new/delete、new[]/delete[]
分别看一下,不匹配会发生什么
6.1内置类型
int main()
{int* ptr1 = new int;free(ptr1);int* ptr2 = new int[10];free(ptr2);return 0;
}
我们执行上述代码,发现编译器并不会报错,因为new 也是通过malloc 来申请空间,通过free 释放的,对于内置类型,我们直接使用free 释放是没有问题的。
6.2自定义类型
定义如下类,之后的代码会用下面的类来创建对象申请空间(没有用到的地方会说明):
class A
{
public:A(int a = 0){_a = a;cout << "A(int a = 0)" << " " << _a << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
new – free
int main()
{A* ptr1 = new A;free(ptr1);return 0;
}
我们看到,这样的代码执行起来编译器也是不会报错的,只是没有执行析构函数,这种情况就要分类讨论了
-
无需要释放的资源 :就像这个A类,它执行不执行析构函数都是无所谓的,因为它对象内没有在额外申请空间,我们只需要释放掉它new出来的即可,这一点free是可以做到的。
-
有需要释放的资源 :我们将上面的代码修改一下,在来运行
class B { public:B(int a = 4){_pa = new int[a];cout << "B(int a = 0)" << endl;}~B(){delete[] _pa;cout << "~A()" << endl;} private:int* _pa; };int main() {B* ptr = new B;free(ptr);return 0; }
观察上面的代码,我们free 只是将ptr 指向的空间释放,而对象ptr 内 _pa 指向的空间却没有释放,这就造成内存泄漏 ,这是很严重的事情,而C/C++中,我们自己申请的内存需要我们自己释放,编译器是不会管的,也不会检查出内存泄漏 的,依然会正常运行。
所以delete 的顺序为先调用析构函数,释放对象内的资源,之后operator delete 释放掉对象的空间。
关于内存泄漏的危害我举个例子:如果一个程序一直在运行,而它存在内存泄漏,那它会一直消耗空间,直到程序无法运行,这是很严重的问题。
我们使用下面的代码来检测,一个程序可以开辟的最大空间(我使用的是VS2019)
int main() {int size = 0;while (1){int* ptr = (int*)malloc(sizeof(int)*2*1024);size += 1;//每次开辟1KB的空间if (ptr == nullptr){break;}}cout << size / 1024 << "MB" << endl;return 0; }
结论: new和malloc系列,底层实现机制有关联交叉。不匹配使用可能出现问题,也可能没有问题,所以大家一定要匹配使用。
拓展:
如果对java有一定了解,应该知道java是没有释放内存这一说的,因为它有一个垃圾回收的机制叫做GC,当我们new一个对象GC就会记录下来,使用过后需要释放该对象时,JVM(java虚拟机) 就会实现这一机制,释放空间。
至于C++为什么不搞这样的机制,因为C/C++是极度追求性能的,GC 这样的机制一定程度上会对性能造成影响,所以C++需要程序员自己释放,以此提高性能。
从学习语言的角度,有GC也并不就是一件好事,虽然用起来方便,但学习Java的每个人都要懂得GC 这个复杂的机制。
new[]–free/new[]–delete
观察下面两段代码及运行结果:
代码1:
int main()
{A* ptr = new A[4];free(ptr);return 0;
}
编译器报错无法正常运行。
代码2:
int main()
{A* ptr = new A[4];delete ptr;return 0;
}
编译器报错无法正常运行。
这两段代码报错的原因和析构函数无关,就像上一段讲的,析构函数哪怕不调用,最坏是内存泄漏,编译还是可以执行的,不会突然报错,报错的原因在于new 开辟连续空间的机制
我们先来看正确的写法:
A* ptr = new A[4];delete[] ptr;
使用new申请连续的空间时,我们在类型后的中括号内填入了数字4告诉编译器,需要申请4个A类型的空间,需要调用4次构造函数,而在delete时,却没有告诉编译器到底调用几次析构函数(释放多少空间编译器会记录,我们使用malloc为内置类型开辟连续的空间时,也没有告诉编译器需要free多大的空间就是证明),那编译器是怎么知道要调用几次析构函数的?
在new开辟空间时,编译器会在开辟的空间起始地址处向前在开辟4个字节的空间,用来存放需要调用的析构函数个数(只用来存储调用几次析构,释放空间的大小编译器会使用其他办法记录),若释放空间时,写法为
delete[]
,释放空间会包含这4个字节,也就是释放空间时,指针指向的起始位置为这四个字节的首地址, 也就知道了需要调用几个析构函数,若写法为delete/free
,则不会去理会起始位置前的这四个字节,指针指向的位置就是申请的空间的起始位置, 只是按照步骤走下去(delete调用一次析构然后释放空间,free直接释放空间),那4个存储数字的字节被保留下来,释放空间的指针位置不对,因此导致编译器报错。
- 一般程序崩溃都是指针指向的问题,这个就是指向的初始位置不对,像内存泄漏是不会崩溃的。
这里还要说明一点,我们在定义A类时,我们自己写了析构函数,若我们自己没写,则使用new[]/fee、new[]/delete 是不会报错的
class A
{
public:A(int a = 0){_a = a;cout << "A(int a = 0)" << " " << _a << endl;}//~A()//{// cout << "~A()" << endl;//}
private:int _a;
};
int main()
{A* ptr1 = new A[4];free(ptr1);A* ptr2 = new A[4];delete ptr2;return 0;
}
如上,当我们将析构函数注释后,类内就只有编译器自己的默认析构函数,这时编译器会认为没有调用析构函数的必要, 也就不需要在开辟4个字节来存储需要调用析构函数的次数,编译器正常运行。
注意: 再次强调,因为C++的语法和底层比较复杂,哪怕我们知道了怎么开辟和释放空间编译器不会报错,但终究会造成问题,如自己的使用失误,误导他人等等,我们还是坚持遵守C++的语法,配套使用malloc/free、new/delete、new[]/delete[] ,不交叉使用。
7.定位new表达式
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
7.1使用格式:
new(place_address)type 或 new(place_address)type(initializer_list)
place_address必须时一个指针,initializer_list是类型的初始化列表
7.2使用场景:
如下,我们使用malloc来申请一块自定义类型的空间,申请后,这块空间是没有办法自动调用构造函数的,只能通过定位new 来调用构造函数初始化,释放时则直接调用析构函数即可。
class A
{
public:A(int a = 0){_a = a;cout << "A(int a = 0)" << " " << _a << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};int main()
{A* ptr = (A*)malloc(sizeof(A));new(ptr)A(1);//定位new,传参//new(ptr)A;//定位new,不传参ptr->~A();//调用析构函数return 0;
}
想必大家都有疑问,为什么要写的这么复杂,直接new一个对象出来不就好了
A* ptr = new A;delete ptr;
凡是存在必然会有它一定的道理,我们一般使用new是向操作系统的堆来申请空间,但操作系统分配空间效率上会有些慢,所以有些地方如果需要频繁的申请内存就会有一个内存池,用来存储需要分配的空间并且效率要高于操作系统,同时内存池分配出的内存没有初始化,如果是自定义类型的对象, 需要使用new的定义表达式进行初始化。
7.3内存池
接着我们来看一下内存池的工作流程:
-
当内存池内有内存时,我们直接向其申请,它就会分配给我们空间
-
当内存池内没有内存时,我们直接向其申请,它会先和操作系统申请,告诉操作系统自己没有内存了,操作系统就会返回其大量内存空间,使其短时间内不会在缺少内存,防止效率下滑。
8.面试题
下面是一道面试题,不建议大家去背,做到理解记忆最好
malloc/free和new/delete的区别
- malloc和free是函数,new和delete是操作符
- malloc申请的空间不会初始化,new可以初始化
- malloc申请空间时,需要手动计算空间的大小并传递,new只需要在其后跟上空间的类型即可,如果是多个对象,[]中指定对象个数即可。
- malloc的返回值为void*,在使用时必须强转,new不需要,因为new后跟的是空间的类型。
- malloc申请空间失败时,返回的是NULL,因此使用必须判空,new不需要,但是new需要捕获异常。
- 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。
9.总结和博客思维导图
对于内存管理,C/C++几乎类似,只是C++在C的基础上做出了更适合面向对象的调整
- 增加了new/delete
- 针对自定义类型更好的调用构造和析构函数
相关文章:

【C/C++】内存管理详解
目录内存布局思维导图1.C/C内存分布数据段:栈:代码段:堆:2.C语言中动态内存管理方式3.C内存管理方式3.1new/delete操作内置类型3.2new和delete操作自定义类型4.operator new 与 operator delete函数5.new和delete的实现原理5.1内置类型5.2自定…...

Android ProcessLifecycleOwner 观察进程生命周期
文章目录简介使用依赖用法1,结合 LiveData用法2,获取 owner的 lifecycle 实例,并对 lifecycle 添加观察者简介 ProcessLifecycleOwner 直译,就是,进程生命周期所有者。 通过 DOC 注释了解到: Lifecycle.E…...

如何编写一个 npm 插件?
提到写 npm 插件,很多没搞过的可能第一感觉觉得很难,无从下手,其实不然。 我们甚至写个简单的 console.log(hello word),都是可以当成一个插件发布上去的。 其实无从下手的主要难点还是在于你的具体要做的功能逻辑,这…...

mapstruct- 让VO,DTO,ENTITY转换更加便捷
mapstruct- 让VO,DTO,ENTITY转换更加便捷 1. 简介 MapStruct是一个代码生成器,简化了不同的Java Bean之间映射的处理,所谓映射指的就是从一个实体变化成一个实体。例如我们在实际开发中,DAO层的实体和一些数据传输对…...

IAR警告抑制及还原
工作中需要临时抑制 警告 Pa084,源代码如下: sy_errno_t sy_memset_s(void *dest, sy_rsize_t dmax, int value, sy_rsize_t n) { sy_errno_t err; if (dest NULL) { return SY_ESNULLP; } if (dmax > SY_RSIZE…...

工厂模式(Factory Pattern)
1.什么是工厂模式 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。 2.工厂模式的作用 实现创建者和调用者的分离 3.工厂模式的分类 简单工厂模式工厂方法模式抽象工厂模式 4.工厂模式的优缺点 优…...

JavaScript语法学习--《JavaScript编程全解》
《JavaScript编程全解》 JavaScript琐碎基础 0.前言 1.RN: react native是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,支持iOS和安卓两大平台。 2.ts与js js:是弱…...

linux安装极狐gitlab
1. 官网寻找安装方式 不管我们使用任何软件,最靠谱的方式就是查看官方文档。gitlab提供了相应的安装文档,并且有对应的中文文档。地址如下: https://gitlab.cn/install/ 我在这里以CentOS作为安装示例,大家可根据自己的需要选择…...

软考高级信息系统项目管理(高项)原创论文——人力资源管理
人力资源管理 某市某国有装备制造公司智能安防信息管控平台项目是在公司推进企业信息化进程和实现企业可持续发展的背景下于2016年8月提出来的,我公司积极应标并最终顺利中标,而我有幸被任命为项目经理,担任起该项目的管理工作。该项目投资金额为530万元,其中软件部分为360…...

Java Lambda表达式 匿名内部类 函数式接口(FunctionalInterface)
Java Lambda表达式定义背景示例匿名类实现Lambda表达式实现对比匿名类和Lambda实现Lambda表达式(调用)说明Lambda表达式的语法Java 1.8 新特性:函数式接口jdk 1.8 自带的函数式接口 (举例)定义 参考Oracle官网&#x…...

javaEE 初阶 — 流量控制与拥塞控制
文章目录1. 流量控制2. 拥塞控制TCP 工作机制:确认应答机制 超时重传机制 连接管理机制 滑动窗口 1. 流量控制 流量控制是一种干扰发送的窗口大小的机制,滑动窗口,窗口越大,传输的效率就越高(一份时间,…...

HTML自主学习 - 2
一、表格 基本语法 <table><tr><td>单元格内容1</td><td>单元格内容2</td><td>单元格内容3</td></tr></table> 1、<table> </table>标签用于定义表格 2、<tr> </tr>标签用于定义表格的…...

【转载】通过HAL库实现MODBUS从机程序编写与调试-----STM32CubeMX操作篇
通过HAL库实现MODBUS从机程序编写与调试-----STM32CubeMX操作篇[【STM32】RS485 Modbus协议 采集传感器数据](https://blog.csdn.net/qq_33033059/article/details/106935583)基于STM32的ModbusRtu通信--ModbusRtu协议(一)基于STM32的ModbusRtu通信--终极Demo设计(二)STM32RS48…...

【C++】string类(上)
文章目录1.为什么要学习string类2.标准库中的string类1.string分类2.string类对象的常见构造1.string3. string类对象的容量操作1.size2.capacity3.reserve4.resize扩容初始化删除数据4. string类对象的修改操作1.push_back2.append3.operator1.为什么要学习string类 c语言的字…...

Java泛型
文章目录一、泛型介绍1. 背景2. 概念3. 好处二、泛型声明泛型类型符号泛型声明方式三、类型擦除1. 什么是类型擦除桥接方法2. 为何需要类型擦除3. 类型信息并未完全擦除四、泛型使用1. 泛型类2. 泛型接口3. 泛型方法五、泛型扩展1. 泛型的上下边界泛型的上边界泛型的下边界2. 泛…...

07 分布式事务Seata使用(2)
1、Seata是什么 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS&#x…...

c++练习题5
5.在C语言中,程序运行期间,其值不能被改变的量叫 常量 。 6.符号常量是指用一个符号名代表一个常量。 7.整型常量和浮点型常量也称为 数值常量 ,它们有正负之分。 9.在C中,变量是 其值可以改变的量 。 …...

Python 高级编程之正则表达式(八)
文章目录一、概述二、正则表达式语法1)字符匹配2)字符集合3)定位符4)分组1、定义分组2、引用分组3、命名分组三、Python 的 re 模块1)re.match() 方法2)re.search() 方法3)re.match() 与 re.sea…...

pynrrd常用操作解析
目录依赖安装官方文档常用操作1. 读部分nrrd.read()nrrd.read_header()nrrd.read_data()2. 写部分nrrd.write()依赖安装 pip install pynrrd官方文档 https://pynrrd.readthedocs.io/en/stable/ 常用操作 1. 读部分 nrrd.read() nrrdpath "your nrrd file path"…...

数据结构:链表基础OJ练习+带头双向循环链表的实现
目录 一.leetcode剑指 Offer II 027. 回文链表 1.问题描述 2.问题分析与求解 (1) 快慢指针法定位链表的中间节点 (2) 将链表后半部分进行反转 附:递归法反转链表 (3) 双指针法判断链表是否回文 二.带头双向循环链表的实现 1.头文件 2.节点内存申请接口和链表初始化接口…...

计算机视觉方向地理空间遥感图像数据集汇总
文章目录1.DSTL卫星图像数据集/Kaggle竞赛2.Swimming Pool and Car Detection/Kaggle竞赛3.SpaceNet Challenge 3数据集4.RarePlanes数据集5.BigEarthNet数据集6.NWPU VHR-10数据集7.UC Merced Land-Use数据集8.Inria Aerial Image Labeling数据集9.RSOD数据集1.DSTL卫星图像数…...

信息系统项目管理师真题精选(一)
1.信息系统的( )决定了系统可以被外部环境识别,外部环境或者其他系统可以按照预定的方法使用系统的功能或者影响系统的行为。A.可嵌套性B.稳定性C.开放性D.健壮性2、在实际的生产环境中,( )能使底层物理硬件…...

信息系统项目管理师刷题知识点(持续更新)
主要记录自己在备考高项过程中知识点 信息系统项目管理师刷题知识点(按刷题顺序排列) 1.信息技术应用是信息化体系六要素中的龙头,是国家信息化建设的主阵地,集中体现了国家信息化建设的需求和效益。 2.原型化方法也称为快速原型法…...

RabbitMq及其他消息队列
消息队列中间价都有哪些 先进先出 Kafka、Pulsar、RocketMQ、RabbitMQ、NSQ、ActiveMQ Rabbitmq架构 消费推拉模式 客户端消费者获取消息的方式,Kafka和RocketMQ是通过长轮询Pull的方式拉取消息,RabbitMQ、Pulsar、NSQ都是通过Push的方式。 pull类型…...

Toolformer: Language Models Can Teach Themselves to Use Tools
展示了LM可以通过简单的API教自己使用外部工具,并实现两个世界的最佳效果。我们介绍了Toolformer,这是一个经过训练的模型,可以决定调用哪些API,何时调用,传递哪些参数,以及如何将结果最好地纳入未来的标记…...

悲观锁与乐观锁
何谓悲观锁与乐观锁 乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。 悲观锁 总是假设最坏的情况,每次去拿数据…...

LeetCode 25. K 个一组翻转链表
原题链接 难度:hard\color{red}{hard}hard 题目描述 给你链表的头节点 headheadhead , kkk 个节点一组进行翻转,请你返回修改后的链表。 kkk 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 kkk 的整数倍…...

朗润国际期货招商:历次科技风头下巨头的博弈
历次科技风头下巨头的博弈 VR/AR、区块链、折叠屏、元宇宙、AIGC五轮科技风头下巨头们都进场了吗? VR/AR硬件 谷歌:2014年入局,推出AR眼镜 百度:未入局 京东:未入局 腾讯:传要开发 亚马逊࿱…...

配置中心Config
引入依赖<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.6.RELEASE</version></parent><properties><spring-cloud.version>Finchley.SR…...

【原创】java+jsp+servlet学生信息管理系统(jdbc+ajax+filter+cookie+分页)
一直想写一个比较基础的JavaWeb项目,然后综合各种技术,方便Java入门者进行学习。学生信息管理系统大家一般接触的比较多,那么就以这个为例来写一个基础项目吧。 需求分析: 使用jspservletmysql开发的学生信息管理系统࿰…...