Categorías
Python

Los servidores de pruebas API externa Con Mock

 

Tabla de Contenidos

  • memoria Es un libro vacío
  • Gestión de memoria: desde el hardware al software
  • grupos de memoria ManagementPoolsBlocksArenas
  • El defecto de Python Implementación
  • El Global intérprete de bloqueo (GIL)
  • Garbage Collection
  • de CPython
  • Piscinas bloques
  • Arenas
  • Conclusión
  • bloques
  • Arenas

vez se ha preguntado cómo Python maneja sus datos detrás de las escenas? ¿Cómo se almacenan las variables en la memoria? ¿Cuándo se eliminan?

En este artículo, vamos a hacer una inmersión profunda en la parte interna de Python para entender cómo se maneja la gestión de memoria.

Al final de este artículo, usted:

  • Más información sobre computación de bajo nivel, específicamente en lo relativo a la memoria
  • Comprender cómo Python abstrae operaciones de bajo nivel
  • Aprender acerca de los algoritmos de gestión de la memoria interna de Python

Comprender internos de Python también le dará una mejor idea de algunos de los comportamientos de Python. Con suerte, obtendrá una nueva apreciación de Python también. Tanto la lógica que está sucediendo detrás de las escenas para asegurar que su programa funciona de la forma esperada. Bono

gratuito: 5 pensamientos sobre Python Maestría, un curso gratuito para los desarrolladores de Python que muestra la hoja de ruta y la mentalidad que necesita para tomar sus habilidades de Python al siguiente nivel.

memoria Es un libro vacío

Puede comenzar por pensar en la memoria de un ordenador como un libro vacío destinado para cuentos. No hay nada escrito en las páginas todavía. Con el tiempo, diferentes autores va a llegar. Cada autor quiere un poco de espacio para escribir su historia en.

Puesto que no se les permite escribir uno sobre el otro, se debe tener cuidado con las páginas que escriben. Antes de que comiencen a escribir, consultan el gerente del libro. El director, entonces decide en qué parte del libro que se les permita escribir.

Puesto que este libro es de alrededor durante mucho tiempo, muchas de las historias en que ya no son relevantes. Cuando nadie lee o hace referencia a las historias, se retiran para dejar sitio a nuevas historias.

En esencia, la memoria del ordenador es como el libro vacío. De hecho, es común llamar de longitud fija bloques contiguos de memoria páginas , por lo que esta analogía es bastante bien.

Los autores son como diferentes aplicaciones o procesos que necesitan para almacenar datos en la memoria. El gerente, quien decide donde los autores pueden escribir en el libro, juega el papel de un administrador de memoria de tipo. La persona que retira las viejas historias para hacer espacio para los nuevos es un recolector de basura.

Memory Management: Gestión del hardware al software

La memoria es el proceso por el cual las aplicaciones de lectura y escritura de datos. Un gestor de memoria determina dónde colocar los datos de una aplicación. Dado que hay un trozo finito de memoria, como las páginas de nuestra analogía del libro, el director tiene que encontrar algo de espacio libre y proporcionarla a la aplicación. Este proceso de proporcionar la memoria generalmente se llama memoria asignación .

Por otro lado, cuando los datos ya no es necesario, se puede eliminar, o liberado . Pero liberado a dónde? ¿De dónde vino esta “memoria” viene?

En algún lugar de su ordenador, hay un dispositivo de almacenamiento de datos física cuando se está ejecutando sus programas Python. Hay muchas capas de abstracción que el código Python pasa por delante de los objetos consiguen realmente al hardware sin embargo.

Una de las principales capas por encima del hardware (como RAM o un disco duro) es el sistema operativo (OS). Se lleva a cabo (o rechaza) las solicitudes de leer y escribir de memoria.

Por encima del sistema operativo, hay aplicaciones, una de las cuales es la implementación de Python por defecto (incluido en su sistema operativo o descargar desde python.org.) La gestión de memoria para su código Python está a cargo de la aplicación Python. Los algoritmos y estructuras que la aplicación Python utiliza para la gestión de la memoria es el foco de este artículo.

el valor por defecto de Python Implementación

La implementación de Python por defecto, CPython, es en realidad escrito en el lenguaje de programación C.

primera vez que oí esto, me voló la cabeza. Un lenguaje que está escrito en otro idioma ?! Bueno, no realmente, pero más o menos. idioma

La pitón se define en un manual de referencia escrito en Inglés. Sin embargo, ese manual no es del todo útil por sí mismo. Usted todavía necesita algo de interpretar el código escrito en base a las reglas del manual.

También necesita algo para ejecutar código interpretado en realidad en un ordenador. La implementación de Python por defecto cumple los dos dichos requisitos. Convierte tu código Python en instrucciones que a continuación se ejecuta en una máquina virtual.

Nota: Las máquinas virtuales son como equipos físicos, sino que se implementan en software. Por lo general procesan las instrucciones básicas similares a las instrucciones de montaje.

Python es un interpretarse lenguaje de programación. Su código Python en realidad se compila hasta más instrucciones legibles por ordenador llamado código de bytes. Estas instrucciones consiguen interpretarse por una máquina virtual cuando se ejecuta el código.

Has visto alguna vez un archivo o una carpeta .pyc __pycache__? Ese es el código de bytes que consigue interpretado por la máquina virtual. Es importante señalar que existen implementaciones distintas de CPython

Se. IronPython compila abajo para ejecutarse en Microsoft de Common Language Runtime. Jython compila a código de bytes de Java para ejecutar en la máquina virtual de Java. Luego está PyPy, pero que merece su propio artículo en su totalidad, por lo que sólo menciono de pasada.

A los efectos de este artículo, me centraré en la gestión de la memoria realizada por la implementación predeterminada de Python, CPython.

Negación : Mientras que una gran cantidad de esta información va a llevar a través de nuevas versiones de Python, las cosas pueden cambiar en el futuro. Tenga en cuenta que la versión de referencia para este artículo es la actual versión más reciente de Python, 3.7.

bien, así CPython está escrito en C, y se interpreta el código de bytes de Python. ¿Qué tiene esto que ver con la gestión de memoria? Así, la memoria existen algoritmos y estructuras de gestión en el código CPython, en C. Para entender la gestión de memoria de la Python, usted tiene que conseguir una comprensión básica de por sí CPython.

CPython está escrito en C, que no soporta de forma nativa la programación orientada a objetos. Debido a esto, hay un poco de diseños interesantes en el código CPython.

Usted puede haber oído que todo en Python es un objeto, incluso tipos como int y str. Bueno, es cierto en un nivel de aplicación CPython. Hay una estructura llamada PyObject, que utiliza todos los demás objetos en CPython.

Nota: Una estructura o estructura , en C es un tipo de datos personalizada que agrupa a diferentes tipos de datos. Para comparar con lenguajes orientados a objetos, es como una clase con atributos y no hay métodos.

El PyObject, el gran padre de todos los objetos en Python, contiene sólo dos cosas:

  • ob_refcnt: cuenta de referencia
  • ob_type: puntero a otro tipo

El recuento de referencia se utiliza para la recolección de basura. Entonces usted tiene un puntero al tipo de objeto real. Ese tipo de objeto es simplemente otra estructura que describe un objeto de Python (como un diccionario o int).

Cada objeto tiene su propio gestor de memoria objeto específico que sabe cómo conseguir la memoria para almacenar dicho objeto. Cada objeto tiene también un deallocator memoria específica a objetos que “libera” la memoria una vez que se ya no es necesaria.

Sin embargo, hay un factor importante en todo esto de asignar y liberar memoria. La memoria es un recurso compartido en el ordenador, y las cosas malas pueden suceder si dos procesos diferentes intentan escribir en el mismo lugar al mismo tiempo.

La intérprete de bloqueo global (GIL)

El GIL es una solución al problema común de hacer frente a los recursos compartidos, como la memoria de un ordenador. Cuando dos subprocesos intentan modificar el mismo recurso al mismo tiempo, pueden pisar los pies de los demás. El resultado final puede ser un lío ilegible, donde ninguno de los extremos hilos con lo que querían.

Consideremos la analogía del libro de nuevo. Supongamos que dos autores tenazmente deciden que es su turno para escribir. No sólo eso, sino que tanto necesita para escribir en la misma página del libro al mismo tiempo.

Cada uno de ellos ignoran las otras de tratar de crear una historia y comienzan a escribir en la página. El resultado final es de dos pisos en uno encima del otro, lo que hace que toda la página totalmente ilegible.

Una solución a este problema es un candado, global sobre el intérprete cuando un hilo está interactuando con el recurso compartido (la página en el libro). En otras palabras, sólo un autor puede escribir a la vez. GIL de

Python logra esto mediante el bloqueo de la totalidad del intérprete, lo que significa que no es posible para otro hilo a paso en la actual. Cuando CPython maneja la memoria, se utiliza el GIL para asegurarse de que lo hace de manera segura.

hay pros y contras a este enfoque, y el GIL está muy debatido en la comunidad de Python. Para leer más sobre el GIL, yo sugiero revisar ¿Cuál es el pitón Global intérprete de bloqueo (GIL) ?.

basura de revisita de Colección

Let la analogía del libro y se supone que algunas de las historias en el libro están consiguiendo muy antiguo. Nadie está leyendo o con referencia a esas historias más. Si nadie está leyendo algo o referencia a ella en su propio trabajo, usted podría deshacerse de él para hacer espacio para la nueva escritura.

Ese viejo, escrito sin referenciar podría compararse a un objeto en Python cuyo recuento de referencia se ha reducido a 0. Recuerde que todos los objetos de Python tiene un contador de referencia y un puntero a un tipo.

El contador de referencias se incrementa por varias razones diferentes. Por ejemplo, el recuento de referencia se incrementará si lo ha asignado a otra variable:

numbers = [1, 2, 3]
# Reference count = 1
more_numbers = numbers
# Reference count = 2

También aumentará si se pasa el objeto como un argumento:

total = sum(numbers)

Como último ejemplo, el recuento de referencia se incrementará si se incluye el objeto en una lista:

matrix = [numbers, numbers, numbers]

Python le permite inspeccionar el recuento de referencia actual de un objeto con el módulo sys. Puede utilizar sys.getrefcount (números), pero tenga en cuenta que pasa en el objeto a getrefcount () aumenta el recuento de referencia en 1.

En cualquier caso, si el objeto sigue siendo necesaria para quedarse en su código, su recuento de referencia es mayor que 0. una vez que cae a 0, el objeto tiene una función específica desasignación que se llama que “libera” la memoria de modo que otros objetos puede utilizarlo.

Pero ¿qué significa “liberar” la memoria, y cómo utilizar otros objetos que? derecho salto Vamos a la gestión de la memoria de CPython. de

CPython Gestión de memoria

Vamos a inmersión profunda en la arquitectura y la memoria de algoritmos CPython, por lo que el cinturón de seguridad.

Como se ha mencionado antes, hay capas de abstracción del hardware físico a CPython. El sistema operativo (OS) abstrae la memoria física y crea una capa de memoria virtual que las aplicaciones (incluyendo Python) el acceso lata.

Un sistema operativo específico virtuales administrador de memoria recorta un trozo de memoria para el proceso de Python. Las cajas grises más oscuros en la imagen de abajo son ahora propiedad del proceso de Python.

Python utiliza una parte de la memoria para uso interno y memoria no objeto. La otra parte está dedicada al almacenamiento de objetos (el int, dict, y similares). Tenga en cuenta que esto se simplifica un poco. Si desea que la imagen completa, se puede extraer el código fuente CPython, donde sucede toda la gestión de esta memoria.

CPython tiene un asignador de objeto que es responsable de la asignación de memoria dentro del área de memoria de objetos. Este asignador objeto es donde la mayoría de la magia sucede. Que es llamado cada vez que un nuevo espacio necesidades objeto asignado o borrado.

Normalmente, la adición y la eliminación de los datos para Python objetos como int lista y no implica demasiados datos a la vez. Por lo que el diseño del asignador está sintonizado para trabajar bien con pequeñas cantidades de datos a la vez. También trata de no asignar memoria hasta que sea absolutamente necesario.

Los comentarios en el código fuente de describir el asignador como “una forma rápida, para fines especiales asignador de memoria para los pequeños bloques, que se utilizará en la parte superior de un malloc de propósito general.” En este caso, malloc es función de biblioteca de C como la asignación de memoria.

Ahora vamos a mirar a la estrategia de asignación de memoria de CPython. En primer lugar, hablaremos de las 3 piezas principales y cómo se relacionan entre sí.

Arenas son las más grandes trozos de la memoria y están alineados en un límite de página en la memoria. Un límite de la página es el borde de un trozo de longitud fija contiguo de memoria que utiliza el sistema operativo. Python asume el tamaño de página del sistema es de 256 kilobytes.

Dentro de las arenas son piscinas, que son una página de memoria virtual (4 kilobytes). Estos son como las páginas de nuestra analogía del libro. Estas piscinas se fragmentan en bloques más pequeños de memoria.

Todos los bloques en un reservorio determinado son de la misma “clase de tamaño.” Una clase de tamaño define un tamaño de bloque específica, dada una cierta cantidad de datos solicitados. La tabla a continuación se toma directamente de los comentarios de código fuente:

Por ejemplo, si se solicitan 42 bytes, los datos se coloca en un tamaño de bloque de 48 bytes.

Pools

Pools se componen de bloques de una sola clase de tamaño. Cada grupo mantiene una lista de doble vinculado a otros grupos de la misma clase de tamaño. De esa manera, el algoritmo puede encontrar fácilmente el espacio disponible para un tamaño de bloque dado, incluso a través de diferentes piscinas.

A usedpools lista de pistas todas las piscinas que tienen algo de espacio disponible para los datos para cada clase de tamaño. Cuando se solicita un tamaño de bloque dado, el algoritmo comprueba esta lista usedpools para la lista de piscinas para que el tamaño del bloque.

piscinas en sí deben estar en uno de los 3 estados: utilizado, completa, o vaciar. Una piscina usada tiene bloques disponibles para los datos a ser almacenados. bloques de una piscina llena todo se asignan y contienen datos. Una piscina vacía no tiene datos almacenados y se puede asignar cualquier clase de tamaño de los bloques cuando sea necesario.

Una lista freepools mantiene un registro de todas las piscinas en el estado vacío. Pero cuando se acostumbren piscinas vacías?

Suponga que su código necesita un trozo de 8 bytes de memoria. Si no hay piscinas en usedpools de la clase de tamaño de 8 bytes, una piscina vacía fresca se inicializa para almacenar bloques de 8 bytes. Esta nueva piscina, entonces se agrega a la lista usedpools para que pueda ser utilizado para futuras solicitudes.

Di una piscina llena libera a algunos de sus bloques porque la memoria ya no es necesaria. Eso piscina conseguiría vuelve a añadir a la lista usedpools por su clase de tamaño.

Se puede ver ahora cómo piscinas pueden moverse entre estos estados (y clases de tamaño de memoria incluso) libremente con este algoritmo.

Bloques

Como se ve en el diagrama anterior, piscinas contienen un puntero a sus bloques “libres” de la memoria. Hay un ligero matiz a la forma en que esto funciona. Este asignador “se esfuerza en todos los niveles (arena, piscina, y de bloque) Nunca tocar a una parte de memoria hasta que sea realmente necesario”, de acuerdo a los comentarios en el código fuente.

Eso significa que un grupo puede tener bloques en 3 estados. Estos estados pueden ser definidos como sigue:

  • intacta: una porción de memoria que no ha sido asignado
  • libre: una parte de memoria que se asignó pero más tarde hizo “libre” por CPython y que ya no contiene datos relevantes
  • asignado: una parte de la memoria que en realidad contiene datos relevantes

el puntero de freeblock a una lista enlazada de bloques libres de memoria. En otras palabras, una lista de lugares disponibles para poner los datos. Si se necesitan más de los bloques libres disponibles, el asignador obtendrá algunos bloques intactos en la piscina.

Como el administrador de memoria hace que los bloques “libres”, esos bloques libres ahora se añaden a la parte delantera de la lista freeblock. La lista actual puede no ser bloques contiguos de memoria, al igual que el primer diagrama agradable. Puede ser algo como el siguiente diagrama:

Arenas

Arenas contienen piscinas. Esas piscinas se pueden utilizar, por completo, o vacío. Arenas sí mismos no tienen como estados explícitos como piscinas hacer sin embargo.

Arenas en cambio se organizan en una lista llamada usable_arenas doblemente enlazadas. La lista está ordenada por el número de piscinas libres disponibles. El menor número de piscinas libres, cuanto más cerca de la arena es al frente de la lista.

Esto significa que se ha seleccionado la arena que es la más completa de los datos para colocar nuevos datos. Pero ¿por qué no al revés? ¿Por qué no los datos lugar donde hay más espacio disponible?

Esto nos lleva a la idea de liberar verdaderamente memoria. Se dará cuenta de que he estado diciendo “libre” entre comillas un poco. La razón es que cuando un bloque se considera “libre”, que la memoria no es realmente liberado de nuevo al sistema operativo. El proceso de Python mantiene asigna y se utilizará más adelante para los nuevos datos. En verdad la liberación de memoria devuelve al sistema operativo para su uso.

Arenas son las únicas cosas que realmente pueden ser liberados. Por lo tanto, es lógico pensar que esas arenas que están más cerca de ser vacío se debe permitir que se vacíe. De esa manera, que la cantidad de memoria puede ser verdaderamente liberado, lo que reduce el consumo de memoria total de su programa de Python.

Conclusión gestión

La memoria es una parte integral del trabajo con ordenadores. manijas pitón de casi todos detrás de las escenas, para bien o para mal.

En este artículo, usted aprendió:

  • Lo que la gestión de memoria es y por qué es importante
  • cómo la implementación de Python por defecto, CPython, está escrito en el lenguaje de programación C
  • Cómo las estructuras de datos y algoritmos trabajan juntos en la memoria del CPython gestión para manejar sus datos

Python abstrae muchos de los detalles arenosos de trabajo con ordenadores. Esto le da la capacidad de trabajar en un nivel más alto de desarrollar su código sin el dolor de cabeza de tener que preocuparse acerca de cómo y donde todos los bytes están siendo almacenados.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *