C++的内存管理
代码区(程序的执行代码) |
数据区(全局变量、常量、静态变量) |
堆区(动态内存) |
栈区(程序中用到的局部数据) |
数据区细分为:自由存储区、全局/静态存储区、常量存储区
所以就有5个数据存储区:
栈区(stack),在执行函数时,函数内的局部变量的存储单元都可以在栈上创建,函数结束后这些内存单元自动被释放。
堆区(heap),由new分配的内存块,一般一个new对应一个delete,如果程序员没有释放,则在程序运行完后,操作系统自动回收
自由存储区,由malloc等申请,由free释放
全局/静态存储区,全局变量和静态变量存放在同一块内存中
常量存储区,里面存放的是常量,不允许修改
c++的浅拷贝(使用编译器默认的复制构造函数、或缺省的复制运算符)
class A a;
b=a;
则b对象copy a对象在stack区的数据,但是并不copy a对象在heap区的数据,而是与a共用heap区的数据。
如果对象有位于heap上的域的话,其不会为拷贝对象分配heap上的空间,而只是指向相同的heap上的同一个地址
C++中会调用拷贝构造函数的情况:
- 一个对象以值传递的方式传入到函数体
- 一个对象以值传递的方式从函数中返回
- 一个对象需要另一个对象初始化
Python的内存管理
在Python中,对象都是通过引用传递的不存在按值传递,Python使用引用计数来跟踪内存中的对象:当一个对象被创建时,就创建了一个引用计数,当这个对象的引用计数为0时,该对象就会被垃圾回收
什么情况在会增加对象的引用计数?
- 对象被创建,如x=1
- 或另外的别名被创建,如y=x
- 或作为参数传递给函数,如 func(x)
- 或作为容器对象的一个元素,如alist=[x,1,'abc']
什么情况下会减少对象的引用计数呢?
- 局部变量离开其作用域
- del y
- 对象被重新复制,x=123
- 对象从一个窗口对象中移除,alist.remove(x)
- 窗口被销毁,del alist
Python浅拷贝的方式(非容器类型的对象没有被拷贝的说法,比如:数字,字符串和其他“原子”类型的对象):
1.完全切片[:];2.使用工厂函数,list(),dict()等;3.使用copy函数
Python深拷贝的方式:使用copy.deepcopy()函数
浅拷贝过程:
对于非容器类类型的对象(字符串,数字)或非可变类型的对象(tuple)中的元素直接复制;对于容器类且可变的(如list,dict)对象里的元素只是把它的引用进行复制。
<pre name="code" class="python"><span style="font-size:14px;">>>> a=[1,'a',['this is a',11]]
>>> b=a[:]
>>> b[0]=2
>>> b[1]='b'
>>> b[2][0]='this is b'
>>> b[2][1]=22
>>> a,b
([1, 'a', ['this is b', 22]], [2, 'b', ['this is b', 22]])</span>
b[0]和b[1]的改变并不会影响a[0],a[1]因为其中的元素1,‘a’都是常量对象,是不可变类型;但是b[2]的改变却会影响a[2],因为该对象是list,是可变对象,因此b[2]只是对a[2]的引用。
注意:如果上述b=a,则表示b是a的引用,a的引用计数+1;此后b的任何动作都会影响a,因为它们指向的是同一块地址。等于号操作并不是浅拷贝,只是传递引用而已。
深拷贝过程:创建一个新的容器对象,并对原来对象中的所有元素进行全新的拷贝
<span style="font-size:14px;">>>> a=[1,'a',['this is a',11]]
>>> import copy
>>> b=copy.deepcopy(a)
>>> b[0]=2
>>> b[1]='b'
>>> b[2][0]='this is b'
>>> b[2][1]=22
>>> a,b
([1, 'a', ['this is a', 11]], [2, 'b', ['this is b', 22]])</span><span style="font-size: 14px;">
</span>
上述b对象的任何改变都不会影响a。