目录
4.operator new与operator delete函数
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
//注:是将常量区的"abcd"拷贝到char2数组
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.代码段(常量区)
globalVar在哪里?(C) staticGlobalVar在哪里?(C)
staticVar在哪里?(C) localVar在哪里?(A)
num1 在哪里?(A)
char2在哪里?(A) *char2在哪里?(A)
pChar3在哪里?(A) *pChar3在哪里?(D)
ptr1在哪里?(A) *ptr1在哪里?(B)
2. 填空题:
sizeof(num1) = 40;
sizeof(char2) = 5; strlen(char2) = 4;
sizeof(pChar3) = 4/8; strlen(pChar3) = 4;
sizeof(ptr1) = 4/8;

说明:
1. 栈又叫堆栈,存储非静态局部变量/函数参数/返回值等等,栈是向下增长的。
2.内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
3.堆用于程序运行时动态内存分配,堆是向上增长的
4.数据段,存储全局数据和静态数据
5.代码段,存储可执行的代码或只读常量
void Test()
{
int* p1 = (int*)malloc(sizeof(int));
free(p1);
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof(int));
int* p3 = (int*)realloc(p2, sizeof(int) * 10);
// 这里不需要free(p2)
free(p3);
}
面试题:
malloc/calloc/realloc的区别?(详见博客[C语言]动态内存管理与柔性数组)
C语言内存管理方式在C++中可以继续使用,但有些地方却无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式,通过new和delete操作符进行动态内存管理。
new/delete操作内置类型
void Test()
{
// 动态申请一个int类型的空间
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请10个int类型的空间
int* ptr6 = new int[3];
delete ptr4;
delete ptr5;
delete[] ptr6;
}

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意,匹配起来使用。
new和delete操作自定义类型
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
// new/delete 和 malloc/free最大区别是 new/delete对于自定义类型除了开空间还会调用构造函数和析构函数
A* p1 = (A*)malloc(sizeof(A));
A* p2 = new A(1);
free(p1);
delete p2;
// 内置类型是几乎是一样的
int* p3 = (int*)malloc(sizeof(int)); // C
int* p4 = new int;
free(p3);
delete p4;
A* p5 = (A*)malloc(sizeof(A) * 10);
A* p6 = new A[10];
free(p5);
delete[] p6;
return 0;
}
一、new[]申请的空间用delete释放
1.内置类型
如int,char,float,double等内置类型这些操作是没有问题的。
int main()
{
//new[]在给内置类型申请空间时,不会存储元素个数,因为自定义类型delete[]时没有析构函数可以调用,free不会出错
//以内置类型int为例
int* ptr = new int[10];
delete ptr;
return 0;
}
如上代码,在执行delete ptr之后,可以看到这一片连续的空间被释放。
2.自定义类型
如C语言中的结构体,枚举,联合体,C++中的类这样操作是有问题的。
class A
{
public:
int _sum;
~A()
{
cout << "调用析构" << endl;
}
};
int main()
{
A* ptr = new A[10];
delete ptr;
return 0;
}
执行delete ptr时程序,只输出了一句"调用析构",便异常终止了。

原理:
new/new[] 和 delete/delete[]的原理:new和delete在底层实际是分别封装了operator new 和 operator delete两个全局函数,而operator new 和 operator delete在底层又分别封装了malloc()和free()。
内置类型为何不会出错:
以上面代码中的内置类型int为例,new int[10]时底层实际是malloc申请了10个int类型数据的空间,当delete时,最底层用free直接释放,显然是没有问题的。
自定义类型为何会出错:
以上面代码中的类A为例,new A[10]时,与int的处理方式不同,对于自定义类型,new在最底层用malloc申请空间后,会调用类A的构造函数,对每个元素进行初始化等操作。
这里需要注意的是,当new[]分配的类型是自定义类型时,new[]会让malloc在分配空间时多申请4个字节,new[]返回的是底层malloc返回地址后向后偏移4字节的地址,如下图所示:
j
具体到new int[10]时,malloc本应该申请10个A类型大小的空间,也就是40个字节,但是malloc申请了44个字节,new返回的指针是malloc返回的指针向后偏移4个字节的地址。
这4个字节存放着所申请自定义元素的个数,是为了确定调用析构函数。
那么前面说free自己可以通过传入一个指针就知道释放多大的空间,那么增加这4个字节来存放元素个数岂不是多此一举?
很有必要讲一下delete[]的原理:delete[]会把new[]所返回的指针向前偏移4个字节的地址返回给free,因此free就能正确的释放掉整片空间。
A* ptr = newA[10]的正确搭配是delete[]ptr,那么delete[]此时获取到的指针是new[]的返回值(并不是malloc所申请空间的首地址),这样的话底层的free并不能通过这个指针释放掉这片空间,但是delete[]还把new所返回的指针向前偏移4个字节位置的地址给free。
多出来4个字节保存着自定义类型元素个数的作用:
一个对象在释放空间前需要调用析构函数来完成一些资源的清理工作,那么问题来了,delete[]没有像new A[10]传参进去,delete[]怎么知道调用多少次析构函数。其实多出来的4个字节存的元素个数就是用来让delete[]知道调用多少次析构函数的。
二、new申请的空间用delete[]释放
1.内置类型
当类型是内置类型时,delete[]和delete一样,所以不会出错。
int main()
{
int* ptr = new int();
delete[] ptr;
return 0;
}
2.自定义类型
会出现错误,原因也是前面讲过的,当类型是自定义类型时,delete[],p会先根据p前面4字节中的元素个数来确定调用析构函数的次数,先调用析构函数,前4个字节的内存是非法内存,其中的值是随机的,所以会调用很多次析构,再把接收的指针p往前4字节的地址给底层的free,但要注意往前面的这4个字节,这4字节是没有被申请空间的
由于free不能释放没有被申请的空间,所以free会出错,而且free也不能通过这个p往前4字节的地址知晓到底释放多大的空间,也会出错(free只能通过malloc返回的地址知道要释放多大空间)。
class A
{
public:
int _sum;
~A()
{
cout << "调用析构" << endl;
}
};
int main()
{
A* ptr = new A();
delete[] ptr;
return 0;
}

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 bytes
void* 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_FINALLY
return;
}
free的实现
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
通过上述两个全局函数的实现知道,operator new 实际也是通过malloc申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete最终是通过free来释放空间的。

内置类型
如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续的空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。
自定义类型
new的原理:
1.调用operator new函数申请空间
2.在申请的空间上执行构造函数,完成对象的构造
delete的原理:
1.在空间上执行析构函数,完成对象中资源的清理工作
2.调用operator delete函数释放对象的空间
new T[N]的原理:
1.调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
2.在申请的空间上执行N次构造函数
delete[]的原理:
1.在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
2.调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
new(place_address) type或者new(place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表
使用场景:
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
// 定位new/replacement new
int main()
{
// p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
A* p1 = (A*)malloc(sizeof(A));
new(p1)A; //注意:如果A类的构造函数有参数时,此处需要传参
p1->~A();
free(p1);
A* p2 = (A*)operator new(sizeof(A));
new(p2)A(10);
p2->~A();
operator delete(p2);
return 0;
}
面试题:
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在释放空间前会调用析构函数完成空间中资源的清理
什么是内存泄漏,内存泄漏的危害?
什么是内存泄漏:内存泄漏指因为疏忽或者错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的丢失,而是应用程序分配某段内存后,因为设计失误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:对于短期的程序,程序只要正常结束(执行return 0语句),操作系统就会回收内存,不会存在内存泄漏,但长期运行的程序出现内存泄漏,影响很大,如操作系统,后台服务等,出现内存泄漏会导致相应越来越慢,最终卡死。
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。
系统资源泄漏:
指程序使用系统分配的资源,比如套接字,文件描述符,管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
如何检测内存泄漏:
在vs下,可以使用windows操作系统提供的_CrtDumpMemoryLeaks()函数进行简单检测,该函数只报出了大概泄漏的多少个字节,没有其他更准确的位置信息。
int main()
{
int* p = new int[10];
// 将该函数放在main函数之后,每次程序退出的时候就会检测是否存在内存泄漏
_CrtDumpMemoryLeaks();
return 0;
}
// 程序退出后,在输出窗口中可以检测到泄漏了多少字节,但是没有具体的位置
Detected memory leaks!
Dumping objects ->
{79} normal block at 0x00EC5FB8, 40 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
Linux下内存泄漏检测工具:

如何避免内存泄漏:
1.工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。但是如果碰上异常时,就算注意释放了,还是可能会出问题,需要智能指针管理才有保证。
2.采用RAII思想或者智能指针来管理资源。
3.有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
4.出问题了使用内存泄工具检测。
总结:
内存泄漏非常常见,解决方案分为两种:1.事前预防型,如智能指针 2.事后查错型,如泄漏检测工具
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我正在使用i18n从头开始构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在rubyonrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi
ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序
我安装了ruby版本管理器,并将RVM安装的ruby实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby。有没有办法让emacs像shell一样尊重ruby的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el
是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s
我想用这两种语言中的任何一种(最好是ruby)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生
你好,我无法成功如何在散列中删除key后释放内存。当我从哈希中删除键时,内存不会释放,也不会在手动调用GC.start后释放。当从Hash中删除键并且这些对象在某处泄漏时,这是预期的行为还是GC不释放内存?如何在Ruby中删除Hash中的键并在内存中取消分配它?例子:irb(main):001:0>`ps-orss=-p#{Process.pid}`.to_i=>4748irb(main):002:0>a={}=>{}irb(main):003:0>1000000.times{|i|a[i]="test#{i}"}=>1000000irb(main):004:0>`ps-orss=-p
这是我在ActiveAdmin中的自定义页面ActiveAdmin.register_page"Settings"doaction_itemdolink_to('Importprojects','settings/importprojects')endcontentdopara"Text"endcontrollerdodefimportprojectssystem"rakedataspider:import_projects_ninja"para"OK"endendend我想做的是,当我单击“导入项目”按钮时,我想在Controller中执行rake任务。但是我无法访问该方法。可能是什
这会导致Ruby出现内存问题吗?我知道如果大小超过10KB,Open-URI会写入TempFile。但是HTTParty会在写入TempFile之前尝试将整个PDF保存到内存吗?src=Tempfile.new("file.pdf")src.binmodesrc.writeHTTParty.get("large_file.pdf").parsed_response 最佳答案 您可以使用Net::HTTP。参见thedocumentation(特别是标题为“流媒体响应机构”的部分)。这是文档中的示例:uri=URI('http://e
我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源