
正文
python函数参数内存 python函数参数的作用
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
python的内存驻留机制(小数据池)
python的内存驻留机制,是一种节省内存的方案,它将int, str, bool类型的数据做成小数据池。当程序要创建字符串等对象前会先检查池中是否有满足的字符串。
驻留机制节省大量的重复内存。在内部,小数据池是由一个全局的dict 维护,该字典中的对象成了单例模式,从而节省内存。
变量 interned 就是全局存放字符串池的字典的变量名 interned = PyDict_New() ,为了让 intern 机制中的字符串不被回收,设置字典时 PyDict_SetDefault(interned, s, s); 将字符串作为键同时也作为值进行设置,这样对于字符串对象的引用计数就会进行两次 +1 操作,这样存于字典中的对象在程序结束前永远不会为 0,这也是 y_REFCNT(s) -= 2; 将计数减 2 的原因。
从函数参数中可以看到其实字符串对象还是被创建了,内部其实始终会为字符串创建对象,但经过 inter 机制检查后,临时创建的字符串会因引用计数为 0 而被销毁,临时变量在内存中昙花一现然后迅速消失。
指定要驻留的字符串:
为什么要进行字符串驻留呢?
总结:
系统维护一个interned全局字典,记录已被驻留的字符串对象,当新字符串a对象需要驻留时,先在interned中查找是否存在,若存在则指向已存在的字符串对象,a对象的引用计数减1,若不存在,则记录a对象到interned中。
相关问答
Q1: python内存管理机制
由于python中万物皆对象python函数参数内存,所以pythonpython函数参数内存的存储问题是对象的存储问题。实际上,对于每个对象,python会分配一块内存空间去存储它。
那么python是如何进行内存分配,如何进行内存管理,又是如何释放内存的呢?
总结起来有一下几个方面:引用计数,垃圾回收,内存池机制
python内部使用引用计数,来保持追踪内存中的对象,Python内部记录python函数参数内存了对象有多少个引用,即引用计数
1、对象被创建 a= 'abc'
2、对象被引用 b =a
3、对象被其python函数参数内存他的对象引用 li = [1,2,a]
4、对象被作为参数传递给函数:foo(x)
1、变量被删除 del a 或者 del b
2、变量引用了其python函数参数内存他对象 b = c 或者 a = c
3、变量离开了所在的作用域(函数调用结束) 比如上面的foo(x)函数结束时,x指向的对象引用减1。
4、在其他的引用对象中被删除(移除) li.remove(a)
5、窗口对象本身被销毁:del li,或者窗口对象本身离开了作用域。
即对象p中的属性引用d,而对象d中属性同时来引用p,从而造成仅仅删除p和d对象,也无法释放其内存空间,因为他们依然在被引用。深入解释就是,循环引用后,p和d被引用个数为2,删除p和d对象后,两者被引用个数变为1,并不是0,而python只有在检查到一个对象的被引用个数为0时,才会自动释放其内存,所以这里无法释放p和d的内存空间
垃圾回收机制: ① 引用计数 , ②标记清除 , ③分带回收
引用计数也是一种垃圾收集机制, 而且也是一种最直观, 最简单的垃圾收集技术.当python某个对象的引用计数降为 0 时, 说明没有任何引用指向该对象, 该对象就成为要被回收的垃圾了.(如果出现循环引用的话, 引用计数机制就不再起作用了)
优点:简单实时性,缺点:维护引用计数消耗资源,且无法解决循环引用。
如果两个对象的引用计数都为 1 , 但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的, 也就是说 它们的引用计数虽然表现为非 0 , 但实际上有效的引用计数为 0 ,.所以先将循环引用摘掉, 就会得出这两个对象的有效计数.
标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。
为了提高效率,有很多对象,清理了很多次他依然存在,可以认为,这样的对象不需要经常回收,可以把它分到不同的集合,每个集合回收的时间间隔不同。简单的说这就是python的分代回收。
具体来说,python中的垃圾分为1,2,3代,在1代里的对象每次回收都会去清理,当清理后有引用的对象依然存在,此时他会进入2代集合,同理2代集合清理的时候存在的对象会进入3代集合。
每个集合的清理时间如何分配:会先清理1代垃圾,当清理10次一代垃圾后会清理一次2代垃圾,当清理10次2代垃圾后会清理3代垃圾。
在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,当创建大量消耗小内存的对象时,频繁调用new/malloc会导致大量的内存碎片,致使效率降低。
内存池的概念就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后再申请新的内存。这样做最显著的优势就是能够减少内存碎片,提升效率。
Python中有分为大内存和小内存:(256K为界限分大小内存)
大小小于256kb时,pymalloc会在内存池中申请内存空间,当大于256kb,则会直接执行 new/malloc 的行为来申请新的内存空间
在python中 -5到256之间的数据,系统会默认给每个数字分配一个内存区域,其后有赋值时都会指向固定的已分配的内存区域
在运行py程序的时候,解释器会专门分配一块空白的内存,用来存放纯单词字符组成的字符串(数字,字母,下划线)
字符串赋值时,会先去查找要赋值的字符串是否已存在于内存区域,已存在,则指向已存在的内存,不存在,则会在大整数池中分配一块内存存放此字符串
Q2: PYTHON 的变量作用域与内存分配
原理:python中任何变量都是对象,所以参数只支持引用传递方式。即通过名字绑定的机制,把实际参数的值和形式参数的名称绑定在一起,形式参数和实际参数指向内存中的同一个存储空间。
回答问题2:
每一次给变量赋值就是把这个名称的值在一个新内存中存储
你print
(id
(a))
会发现每一次f(x),a的内存地址都是新的。所以你的问题二中L=[4,3]
与之前的L[]不是同一个名称,所以append上a就是[4,3,3](简明点就是L=[4,3]与L=[1,2]是两不同名的玩意)
讨论问题1:
在你的程序中a=1,a=2,a=5是int对象的三个实例,所以占用的是三段不同的内存,自然在程序执行完收回内存的时候才会被清理;而L是通过列表的append方法进行变化时,print
(f(1))
(f(2))
(f(5))是对对一个实例进行操作的,所以内存地址不变;
同理print
(f(3,[4,3]))直接给L赋值时,由于
是一个新的列表实例了,内存位置自然变化。
产生以上的问题的根本原因就是python的精髓:万物皆对象
(赋值的过程是对象的实例化)
看完自己的回答后:感觉真的很绕,不过我是尽力了,希望你能看懂,不明白的话,在追问里注明吧!
Q3: python的内存管理机制
论坛
活动
招聘
专题
打开CSDN APP
Copyright © 1999-2020, CSDN.NET, All Rights Reserved
登录
XCCS_澍
关注
Python 的内存管理机制及调优手段? 原创
2018-08-05 06:50:53
XCCS_澍
码龄7年
关注
内存管理机制:引用计数、垃圾回收、内存池。
一、引用计数:
引用计数是一种非常高效的内存管理手段, 当一个 Python 对象被引用时其引用计数增加 1, 当其不再被一个变量引用时则计数减 1. 当引用计数等于 0 时对象被删除。
二、垃圾回收 :
1. 引用计数
引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集技术。当 Python 的某个对象的引用计数降为 0 时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如某个新建对象,它被分配给某个引用,对象的引用计数变为 1。如果引用被删除,对象的引用计数为 0,那么该对象就可以被垃圾回收。不过如果出现循环引用的话,引用计数机制就不再起有效的作用了
2. 标记清除
如果两个对象的引用计数都为 1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的,也就是说,它们的引用计数虽然表现为非 0,但实际上有效的引用计数为 0。所以先将循环引用摘掉,就会得出这两个对象的有效计数。
3. 分代回收
从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。
python函数参数内存的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于python函数参数的作用、python函数参数内存的信息别忘了在本站进行查找喔。







