python和java虚拟机内存管理_Python内存管理(一):预备知识

一、内存的理解

你可以将计算机中的内存理解为一本为短期存储而设计的书。这本书中现在什么都没写,但最终不同的“作者”会来寻求空间,写入他们想写的故事。

由于他们之间不能彼此覆盖,他们在开始写入之前一定要向这本书的管理者申请,由管理者来决定他们写入到哪里。

由于这本书会存在很长的时间,书中的很多故事可能已经不再有意义。当没有人读或者引用故事,这些无意义的故事就会被删除,给新的故事腾出空间。

本质上,电脑内存很像是一本空的书。实际上,内存通常被叫做“固定长度的连续内存块”,所以这个类比是很贴切的。作者就像是不同的应用程序或者进程,需要在内存中存储数据。决定作者写内容位置的管理者则扮演各种各样内存管理器的角色。清除旧故事,给新作者提供空间的人就是垃圾回收机制。

二、内存管理:从硬件到软件

内存管理是应用读取、写入数据的流程。内存管理机制决定了在哪里存储应用数据。

就像是我们上面以书为类比,内存块也是有限的,管理机制必须要找出可用的空间并且将其提供给应用。这个提供内存的过程一般被称作内存分配。

另一方面,当数据不再被需要,那么数据可以被删除,或者被释放。但是释放到哪里呢?这个内存从哪里来的?

在你的计算机的某个位置,当你运行你的Python程序时,有一个实体硬件在存储数据。但是在对象实际到达硬件之前,Python代码要经过很多抽象层。

在硬件之上,其中一个主要的抽象层是默认的Python实现(在OS中内置或者你从http://python.org中下载)Python代码中的内存管理是由Python应用程序处理的。本文聚焦Python应用程序在内存管理中使用的结构和算法。

三、默认的Python实现

默认的Python实现,CPython是使用C语言写的。

是不是很震惊?一种语言是用另一种语言写的?好吧,这不是真的,但多少有点。

Python语言在Python参考文档里有详细的讲解,但是光靠文档并不能覆盖一切,我们还是需要一些东西来编译实际代码。我们也需要在计算机上实际执行编译后的代码。默认的Python实现满足这两个要求,它将你的Python代码转化为指令并且将其运行在虚拟机上。

Python是解释型语言,你的Python代码实际上被编译成更底层,更对计算机友好的bytecode指令。当你运行你的代码时,这些指令被虚拟机编译了。你见过.pyc文件或者__pycache__文件夹吗?那就是被虚拟机编译后的bytecode代码。

必须指出,除了CPython之外,还有别的Python实现。Ironpython编译后在Microsoft 的公共语言运行时上运行。Jython编译后成为Java bytecode,在Java虚拟机上运行,还有PyPy,但这个Python实现值得用一篇文章专门介绍,此处不提。

为了理解Python内存管理,我们将聚焦于Python的默认实现——Cpython中所实现的内存管理。本文中涉及到的知识适用于目前的通用版本——Python3.7

好了,我们知道CPython是用C写的,并且编译为Python bytecode,这和内存管理有什么联系呢?是这样的——内存管理算法和结构存在于CPython代码中,用C写的。为了理解Python中的内存管理,我们需要对CPython有一些基本了解。

CPython是用C写的,它本身并不支持面向对象编程。正因如此,在CPython中有很多有趣的设计。你可能听说过Python中一切皆是对象,甚至诸如int、str这样的类型。确实,在CPython的实现级别是这样的。有一个结构叫做PyObject,在CPython中其他object都在使用它。

C中的一个或者多个结构是将不同数据类型组合在一起的自定义数据类型。与面向对象的语言相比,就像是具有属性且没有方法的类。PyObject,所有Python中对象的老祖宗,仅仅包含如下两个部分:ob_refcnt:引用计数

ob_type: 指针

引用计数用于垃圾回收机制。你现在有一个指针,指向实际对象类型。该对象类型只是另一种用于描述Python对象的结构(例如dict或者int)

每个对象都有自己的特定对象的内存分配器,该分配器知道如何获取存储该对象的内存,每个对象也有特定对象的内存释放器,用于释放不再被需要的内存。

在我们所有关于分配和释放内存的讨论中,有一个重要的因素。内存是计算机中被共享的资源,如果不同的进程同时写入同一位置,糟糕的事情就会发生。

四、全局解释器锁(GIL)

GIL是在解决共享资源,像是内存这类型的共性问题的有效解决办法。当两个线程同时想要修改相同的资源,他们可能会互相“踩脚趾”,最终的结果可能是乱码,在乱码中,两个线程都没有得到想要的结果。

再考虑一下我们那个用书比作内存的比喻。假设两个作者都固执地一定认为该轮上他来写了,而且他们都要写到书的同一页上。他们忽略了其他人也在创作故事,那么结果就是一页上两个故事相互重叠,整个页面完全不可读。

这个问题的解决办法之一是:在一个线程与共享资源交互时,使用单一的全局解释器锁将该资源上锁。也就是说,同一时间只有一个作者可以写作。

Python的全局解释器锁通过锁住整个解释器来实现这一点。这意味着另一个线程不可能踩到当前的解释器。当CPython处理内存时,使用GIL锁来确保安全。

这种方法有利有弊,也在Python社区引起了激烈讨论。

关于全局解释器锁:What is the Python Global Interpreter Lock (GIL)? – Real Python​realpython.com50563a60973e383745b984e7a8a4b24d.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值