垃圾回收机制、 内存溢出、内存泄露

429 篇文章 6 订阅

参考:

python的内存管理机制是什么?:https://www.zhihu.com/question/30747394/answer/2367713248
Python内存管理及释放:https://blog.csdn.net/jiangjiang_jian/article/details/79140742
如何释放Python占用的内存?:https://www.zhihu.com/question/34895986/answer/293213648

变量名个对象和类型

a = 'abcde'
print(a)
a = [1,2,3,4,5]
print(a)

# abcde
# [1, 2, 3, 4, 5]

1、总结一下:变量名没有类型,只有对象才有类型,变量只是引用了不同类型的对象而已。每一个对象都包含了两个头部信息,一个是类型标志符,标识这个对象的类型,以及一个引用的计数器,用来表示这个对象被多少个变量名所引用,如果此时没有变量引用他,那么就可以回收这个对象

2、还是上面那个例子,每当一个变量名被赋予了一个新的对象,那么之前的那个对象占用的空间就会被回收,前提是如果他没有被其他变量名或者对象引用。这种自动回收对象空间的机制叫做垃圾收集机制。

3、总结一下,给一个变量赋一个新的值,并不是替换原始的对象,而是让这个变量去引用完全不同的另一个对象,而原来的对象的引用计数会随之减1。

垃圾回收机制

要理解什么是垃圾回收机制,首先要对内存管理概念有一个基本的认识。内存管理是指操作系统如何进行内存的分配和回收的机制。早期的计算机语言,比如C, 它通过malloc, free函数来向操作系统请求内存和释放内存。 这种机制的优点是内存分配和释放的效率很高。但是它也有着它的缺点,主要表现在对于复杂的系统,存在着大量的内存分配和释放操作。程序员很容易不小心忘记释放内存,从而造成内存的泄露,对于长期运行的软件来讲,这将是一个致命的威胁,因为系统的内存会逐渐被吃光。 因此,更新的编程语言,比如JAVA, C#, 都提供了所谓“垃圾回收的机制”,运行时自身会运行相应的垃圾回收机制。程序员只需要申请内存,而不需要关注内存的释放。垃圾回收器(GC)会在适当的时候将已经终止生命周期的变量的内存给释放掉。GC的优点就在于它大大简化了应用层开发的复杂度,降低了内存泄露的风险

java/python

虽然理论上不如C/C++手动管理得高效, 但手写出来的管理能又好又快是很难做到的, 需要有一定的基础和经验,并且花费一些心智. 值得吗, 不值得. 我宁愿多浪费些内存让自己轻松一些. 当然也有值得的情况, 但不应该事必躬亲对吧.

a = 'abcde'
print(a)
a = [1,2,3,4,5]
print(a)

abcde
[1, 2, 3, 4, 5]

1、创建了一个字符串对象’abcde’,然后创建了一个变量a,将变量a和字符串对象’abcde’相连接,

2、之后又创建了一个列表对象[1,2,3,4,5],然后又将他和a相连接。
种从变量到对象的连接,我们称之为引用,以内存中的指针形式实现。因此直白的说,在内部,变量事实上是到对象内存空间的一个指针,而且指向的对象可以随着程序赋值语句而不断变化。

具体的内部机制是这样的:

python在每个对象中保存了一个计数器,计数器记录了当前指向该对象的引用的数目。一旦这个计数器被设置为0,这个对象的内存空间就会自动回收。当a被赋值给列表对象后,原来的字符串对象‘abcde’的引用计数器就会变为0,导致他的空间被回收。这就使得我们不必像C++那样需要专门编写释放内存空间的代码了

1. 不可变数据类型,可变只的是对象是否可变,即在内存中的值是否可变,不可变指向这个对象的变量也不会变,如果这个变量变化了,说明是指向一个新的对象了

整型(int)赋值:

a = 1
print(id(a))
b = a
print(id(b))
a = a + 1
print(id(a))
c = 1
print(id(c))

输出结果

140721330548992
140721330548992
140721330549024
140721330548992

2. 可变数据类型,可变所以,指变量跟着这个对象,内存里面的值一块变化

以列表(list)为例:

l1 = [1, 2, 3]
print(id(l1)) #
l2 = l1
print(id(l2))
l1.append(4)
print(id(l1))
print(l1)
print(l2)

执行结果:

1933202772296
1933202772296
1933202772296
[1, 2, 3, 4]
[1, 2, 3, 4]

l1 和 l2 指向相同的对象,由于列表是可变(mutable)数据类型,所以 l1.append(4)不会创建新的列表,仍然指向相同的对象。 由于l1 和 l2 指向相同的对象,所以列表变化也会导致l2的值变化。可变对象(列表,字典,集合等)的改变,会影响所有指向该对象的变量。对于不可变对象(字符串、整型、元组等),所有指向该对象的变量的值总是一样的,也不会改变。

Python中的’==’ 和 ‘is’

== 和 is是Python 对象比较中常用的两种方式,== 比较对象的值是否相等, is 比较对象的身份标识(ID)是否相等,是否是同一个对象,是否指向同一个内存地址。

可变,所以同样的值,分配在不同的内存区域

a = [1]
b = [1]
print(id(a))
print(id(b))
print(a == b)
print(a is b)
# 1192219923016
# 1192219923528
# True
# False

不可变,所以同样的值,还是同一个内存

a = 1
b = 1
print(id(a))
print(id(b))
print(a == b)
print(a is b)
# 140721330548992
# 140721330548992
# True
# True

内存溢出、内存泄露

内存溢出,申请不到足够的内存;

内存泄露,无法释放已申请的内存;

两者关系:内存泄露 → 剩余内存不足 → 后续申请不到足够内存 →内存溢出。

1、内存溢出:(Out Of Memory—OOM) 系统已经不能再分配出你所需要的空间,比如系统现在只有1G的空间,但是你偏偏要2个G空间,这就叫内存溢出例子:一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出。比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出。说白了就是我承受不了那么多,那就报错。

2、内存泄漏: (Memory Leak)强引用所指向的对象不会被回收,可能导致内存泄漏,虚拟机宁愿抛出OOM也不会去回收他指向的对象意思就是你用资源的时候为他开辟了一段空间,当你用完时忘记释放资源了,这时内存还被占用着,一次没关系,但是内存泄漏次数多了就会导致内存溢出(关于强引用、弱引用、软引用的区别和联系可以戳这里查看:点击进入)例子:你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。就相当于你租了个带钥匙的柜子,你存完东西之后把柜子锁上之后,把钥匙丢了或者没有将钥匙还回去,那么结果就是这个柜子将无法供给任何人使用,也无法被垃圾回收器回收,因为找不到他的任何信息。比如我们在使用ThreadLocal的时候可能就会发生内存泄露,什么是ThreadLocal,可以戳这里了解:点击进入一般我们所说的内存泄漏指的是堆内存的泄露,堆内存是指程序从堆中分配的,大小随机的用完后必须显示释放的内存,C++/C中有free函数可以释放内存,java中有垃圾回收机制不用程序员自己手动调用释放如果这块内存不释放,就不能再用了,这就叫这块内存泄漏了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值