zoukankan      html  css  js  c++  java
  • Python int 数据数据类型在内存中分配原理

    python代码如下

    import sys
    for i in "abcdefghijkdfasdf;;lblcv":
        byte_list = bytes(i, encoding="utf-8")
        print('*' * 11, byte_list)
        for k in byte_list:
            print(type(k))
            print(sys.getsizeof(k))
            # print(bin(k))
            print(hex(id(k)))
    

      bytes函数将字符串按照encoding 将字符串转换为字节序列;

          utf-8中一个英文字母占1个字节

     执行结果

     关于内存地址的理解如下

    电脑的内存(尤其是指主存)是由许多“内存地址”所组成的,每个内存地址都有一个“物理地址”,能供CPU(或其他设备)访问。一般,只有如BIOS操作系统及部分特定之公用软件(如内存测试软件)等系统软件,能使用机器码的运算对象或寄存器对物理地址定址,指示CPU要求内存控制器之类的硬件设备,使用内存总线或系统总线,亦或分别之控制总线地址总线数据总线,运行该程序之命令。内存控制器的总线是由数条并行的线路所组成的,每条线路表示一个比特。总线的宽度因此依电脑不同,决定了可定址之存储单位数量,以及每一单位内的比特数量。
    计算机程序使用内存地址来运行机器码、存储及截取数据。大多数的应用程序无法得知实际的物理地址,而是使用电脑的内存管理单元及操作系统的内存映射,为“逻辑地址”或虚拟地址定址
     
    内存地址0x0001和内存地址0x0002之间差的是一个byte,而不是一个bit?
    下内存的物理构造,一般内存的外形图片如图1。一个内存是由若干个黑色的内存颗粒构成的。每一个内存颗粒叫做一个chip。
     
    图1.内存外形图
    上面这个内存条有8个chip。每一个chip内部,是由8个bank组成的。其构造如下图:
     
    图2.内存颗粒物理结构
    在每个bank内部,就是电容的行列矩阵结构了。(注意,二维矩阵中的一个元素一般存储着8个bit,也就是说包含了8个小电容)。
     
    图3.bank物理结构

    8个同位置的元素,一起组成在内存中连续的64个bit。如下图
     
    图4.jpg

    通过内存的物理结构我们可以看出,因为在内存中最小单位就是字节。所以操作系统在管理它的时候,最小单位也就是字节了。另外,通过上述的我们还有一个额外发现。那就是在内存中连续的64个bit,其实在内存的物理结构中,并不连续。而是分散在同位置的8个rank上的。

    计算机的存储空间比作一本空白的短篇小说。页面上还没有任何内容。最终,会有不同的作者出现。每个作者都需要一些空间来写他们的故事。

    由于不允许彼此书写,因此必须注意他们能书写的页面。开始书写之前,请先咨询书籍管理员。然后,管理员决定允许他们在书中写什么。

    如果这书已经存在很长时间了,因此其中的许多故事都不再适用。当没有人阅读或引用故事时,它们将被删除以为新故事腾出空间。

    本质上,计算机内存就像一本空书。实际上,调用固定长度的连续内存面块是很常见的,因此这种类比非常适用。

    作者就像需要将数据存储在内存中的不同应用程序或进程。决定作者在书中书写位置的管理员就像是各种存储器管理的角色,删除旧故事为新故事腾出空间的人是垃圾收集者(garbage collector)。

    内存管理是应用程序读取和写入数据的过程。内存管理器确定将应用程序数据放置在何处。

    由于内存有限,类比书中的页面一样,管理员必须找到一些可用空间并将其提供给应用程序。提供内存的过程通常称为内存分配。

    其实如果我们了解内存管理机制,以更快、更好的方式解决问题。

    Python 语音中 一切皆对象,Python对象实现的核心就是一个结构体--PyObject

    PyObject是每个对象必有的内容,可以说是Python中所有对象的祖父,仅包含两件事:

    • ob_refcnt:引用计数(reference count)
    • ob_type:指向另一种类型的指针(pointer to another type)

    Python将部分内存用于内部使用和非对象内存。另一部分专用于对象存储(您的int,dict等)

    Python的内存分配器

    内存结构

    在Python中,当要分配内存空间时,不单纯使用 malloc/free,而是在其基础上堆放3个独立的分层,有效率地进行分配。

    [图片上传失败...(image-22ef57-1588088246750)]
    第 0 层往下是 OS 的功能。第 -2 层是隐含和机器的物理性相关联的部分,OS 的虚拟内 存管理器负责这部分功能。第 -1 层是与机器实际进行交互的部分,OS 会执行这部分功能。 因为这部分的知识已经超出了本书的范围,我们就不额外加以说明了。
    在第 3 层到第 0 层调用了一些具有代表性的函数,其调用图如下。
    [图片上传失败...(image-8142ba-1588088246750)]

    第0层 通用的基础分配器

    以 Linux 为例,第 0 层指的就是 glibc 的 malloc() 这样的分配器,是对 Linux 等 OS 申 请内存的部分。

    Python 中并不是在生成所有对象时都调用 malloc(),而是根据要分配的内存大小来改 变分配的方法。申请的内存大小如果大于 256 字节,就老实地调用 malloc();如果小于等 于 256 字节,就要轮到第 1 层和第 2 层出场了

    第1层处理的信息的内存结构

    根据所管理的内存空间的作用和大小的不同,我们称最小 的单位为 block,最终返回给申请者的就是这个 block 的地址。比 block 大的单位的是 pool, pool 内部包含 block。pool 再往上叫作 arena。

    也就是说 arena > pool > block,感觉很像俄罗斯套娃吧。
    为了避免频繁调用 malloc() 和 free(),第 0 层的分配器会以最大的单位 arena 来保留 内存。pool 是用于有效管理空的 block 的单位。
    arena 这个词有“竞技场”的意思。大家可以理解成竞技场里有很多个 pool,pool 里面漂 浮着很多个 block,这样或许更容易理解一些。

    arena

    Arenas是最大的内存块,并在内存中的页面边界上对齐。页面边界是操作系统使用的固定长度连续内存块的边缘。Python假设系统的页面大小为256 KB。
    [图片上传失败...(image-e2e369-1588088246750)]
    Arenas内有内存池,池是一个虚拟内存页(4 KB)。这些就像我们书中类比的页面。这些池被分成较小的内存块。

    给定池中的所有块均具有相同的“大小等级”。给定一定数量的请求数据,大小类定义特定的块大小。

    第1层总结

    第 1 层的任务可以用一句话来总结,那就是“管理 arena”。

    第2层 Python对象分配器

    第 2 层的分配器负责管理 pool 内的 block。

    block

    pool 被分割成一个个的 block。我们在 Python 中生成对象时,最终都会被分配这个 block (在要求大小不大于 256 字节的情况下)。
    以 block 为单位来划分,这是从 pool 初始化时就决定好的。这是因为我们一开始利用 pool 的时候就决定了“这是供 8 字节的 block 使用的 pool”。
    pool 内被 block 完全填满了,那么 pool 是怎么进行 block 的状态管理的呢?
    block 只有以下三种状态。

    1. 已经分配
    2. 使用完毕
    3. 未使用

    第3层 对象特有的分配器

    对象有列表和元组等多种多样的型,在生成它们的时候要使用各自特有的分配器。

    分配器的总结



    一个内存地址所代表的永远是1个字节,内存的每一个字节都有为一个个编号

    字节是计算机中数据处理的基本单位;1个字节=8个bit

     内存地址只是一个编号,代表一个内存空间;

    内存地址所执行的内存单元大小就是1字节,跟内存地址位数无关;

    内存空间大小就是寻址能力,即能访问到多少个地址

    int在python里是一个类,是不可变数据类型中的一种,一些性质和字符串是一样的,是整型

    32位系统
    int:开销= 10字节,值= 4字节
    float:开销= 8字节,value = 8字节
    
    64位系统
    int:开销= 20字节,值= 8字节
    float:开销= 16个字节,值= 8个字节

    因此,sys.getsizeof(0) 数组元素为0。此时占用24字节(PyObject_VAR_HEAD 的大小)。 sys.getsizeof(456) 需使用一个元素,因此多了4个字节。

    综上,一个int类型占用了28字节,根据内存分配原则,计算机分配了32字节的内存空间

  • 相关阅读:
    golang删除数组某个元素
    golang用通道实现信号量,控制并发个数
    什么是ScaleIO中的forwards rebuild和backwards rebuild?
    SQL Server中的database checkpoint
    如何将thick provision lazy zeroed的VMDK文件转换为thick provision eager zeroed?
    LoadTestAgentResultsLateException in VS2010
    SQL Server Instance无法启动了, 因为TempDB所在的分区没有了, 怎么办?
    VMware vCenter中, 如何辩认虚机上Raw Device Mapping过了的一块物理磁盘?
    SQL Server AlwaysOn Setup Step-By-Step Guide
    TPC-E在populate测试Database时需要注意的一些事项
  • 原文地址:https://www.cnblogs.com/workherd/p/14199648.html
Copyright © 2011-2022 走看看