Compiladores II (96-97 12/06/2015 13:10)- 3.1 - Tema 4. Gestión Compleja de Memoria Asignación Dinámica de la Memoria Lecciones 10,11,12,13.

Slides:



Advertisements
Presentaciones similares
2. Manejo de memoria Manejo de memoria estática
Advertisements

Creación y destrucción de objetos
EQUIPO ·# 3 SISTEMAS OPERATIVOS
Unidad 5 Listas Enlazadas Bibliografía: Algoritmos y Estructuras de datos de Aguilar y Martinez. Unidad 9 Autor: Ing Rolando Simon Titiosky.
Listas enlazadas c++ Prof. Franklin Cedeño.
Programación II Listas
Clase 3: Punteros y Referencias
Funcionamiento, programación
PROGRAMACION DE ESTRUCTURAS DE DATOS
Implementación de archivos
Informática II 1 Diego Fernando Serna RestrepoSemestre 2011/2.
Teoría de lenguajes y compiladores
Tema 3. Optimización de Código
¿Qué es un PUNTERO?: Un puntero es un objeto que apunta a otro objeto. Es decir, una variable cuyo valor es la dirección de memoria de otra variable. No.
CI TEORIA semana 8 Subprogramas o funciones Definición de funciones.
Material de apoyo Unidad 2 Estructura de datos
Estructuras dinámicas de datos, TAD Lista, parte 2
COLAS, IMPLEMENTACIÓN A PARTIR DE LISTAS Y PARA PILAS
Compiladores II ( /04/ :03) Tema 2. Generación de Código para Estructuras Complejas Lecciones 3 y 4.
Extracto del material disponible en Estrategias para la recolección de basura (Garbage Collection.
Igor Santos Grueiro. De este tipo de pilas NO vamos a hablar.
Tema 6: Clases Antonio J. Sierra.
HILOS Y COMUNICACIÓN ENTRE PROCESOS
Nombre, Alcance y Asociaciones (Bindings). Agenda Definición Nombre y Bindings Binding Time Importancia del Binding Time Eventos relacionados a la Asociación.
Práctica 7 AOC. Gestión de la pila Una pila es una estructura de datos caracterizada por que el último dato que se almacena es el primero que se obtiene.
Semana 5 Subprogramas..
ESTRUCTURAS DE DATOS I Conocer, comprender y analizar algunos de los principales tipos de estructuras de datos.
Índice. Revisando conceptos acerca de la memoria.
Estructuras.
Estructura de Datos y Algoritmos
Estructuras de Datos Arreglos.
Clase 10: Estructuras de datos y arreglos.
Estructura de Datos II Equipo 4 Equipo 7 Acosta Montiel Miguel A.
Árboles binarios de búsqueda
Administración de Memoria Memoria Virtual
Sistema de archivos Sistemas operativos.
Programación I Técnico Universitario en Web Dpto. de Informática FCFMyN - UNSL -11-
Tema 10.3: Asignación de Espacio No Contiguo. Tema 10.3: 2 Silberschatz, Galvin and Gagne ©2005 Fundamentos de los Computadores (ITT, Sist. Electr.),
1 Estructuras de Datos Elementales:stacks (pilas), queues (colas), linked lists (listas enlazadas), y rooted trees (árboles con raíz) Agustín J. González.
Asignación de Espacio No Contiguo
Administración de Memoria
Informática Ingeniería en Electrónica y Automática Industrial
Capítulo 7 Gestión de memoria.

TEORIA DE LA INFORMACION INGENIERO ANYELO QUINTERO.
Informática Ingeniería en Electrónica y Automática Industrial
Memoria estática versus dinámica con Estructuras
Programación en C para electrónicos
Listas Ligadas Simples. Definíción I  Es, en sencillas palabras. un grupo de datos organizados secuencialmente, pero a diferencia de los arreglos, la.
PUNTEROS Y REFERENCIAS
Constructor  Un constructor es un método que inicia un objeto inmediatamente después de su creación. De esta forma nos evitamos el tener que iniciar.
Teoría de Sistemas Operativos Administración de Archivos.
Teoría de lenguajes y compiladores
Fundamentos de Programación
Teoría de Sistemas Operativos Memoria Departamento de Electrónica 2º Semestre, 2003 Gabriel Astudillo Muñoz
Introducción a los TADs
PROGRAMACION DE Pilas o Stacks

Conceptos y Lenguaje Imperativo
MEMORIA DINÁMICA.
PUNTEROS. Los punteros son de amplia utilización en programación y muchos lenguajes permiten la manipulación directa o indirecta de los mismos. Su razón.
Listas Dinámicas.
Tema 1. Estructuras de datos Objetivo: Objetivo: El alumno resolverá problemas de almacenamiento, recuperación y ordenamiento de datos y las técnicas de.
Gestión de Memoria – Parte 2
Métodos en Java. Estructura de un programa en Java ► La relación con la vida misma la podemos ver en el siguiente comentario: Imaginemos que dos clases.
Katty Evangelina Hipólito Chi.   Aunque cada maquina tiene un lenguaje ensamblador distinto, el proceso de ensamblador tiene suficiente similitudes.
Lenguaje de Programación II Prof. Rafael Montenegro B. Carrera: T.S.U en Informática Periodo: 2014-I.
1 Tema 10: Administración de la Memoria Sistemas Operativos (Tema 13 en apuntes prof. Rovayo)
UNIVERSIDAD AUTÓNOMA DEL ESTADO DE MÉXICO FACULTAD DE INGENIERÍA COORDINACIÓN DE MATERIAS PROPEDÉUTICAS INGENIERÍA EN SISTEMAS ENERGÉTICOS SUSTENTABLES.
1/50 Ing. Gerardo Chávez Malpartida Administración de Memoria SISTEMAS OPERATIVOS.
Transcripción de la presentación:

Compiladores II ( /06/ :10) Tema 4. Gestión Compleja de Memoria Asignación Dinámica de la Memoria Lecciones 10,11,12,13

Compiladores II ( /06/ :10) Gestión del Heap (memoria dinámica) El heap es un espacio formado por bloques de memoria cuyo tiempo de vida no se conoce en tiempo de compilación. –A estos bloques se accede por apuntador –Hay funciones para pedir y liberar bloques (malloc, free) Tipos de gestión de memoria –Gestion Explicita: el programador llama explicitamente a una función para liberar los bloques de memoria. Métodos: Lista ordenada de bloques libres Bloques etiquetados en los extremos Bloques compañeros –Gestión Implícita: El sistema se encarga de liberar los bloques de memoria que no utilice el programa. Métodos: Marcar y barrer Recolector por copia Contadores de referencias

Compiladores II ( /06/ :10) Lista Ordenada de Bloques Libres Se utiliza una lista de bloques libres ordenada por la dirección inicial del bloque. Cada bloque tiene una cabecera con su tamaño y en el caso de los bloques libres un apuntador al siguiente bloque de la lista Bloque libre Bloque ocupado Lista ordenada de bloques libres Espacio libreTSig Espacio ocupadoT libreTSocupadoTlibreTSocupadoT

Compiladores II ( /06/ :10) Pedir Memoria (I) Pedir n bytes –Buscar en la lista de bloques libres un bloque con Tamaño=n bytes+ tamaño cabecera bloque ocupado (4bytes) Tamaño>=n+tamaño cabecera bloque libre (8bytes)+tamaño cabecera bloque ocupado (4bytes) –Para bloque de tamaño n Sacarlo de la lista de libres y retornar apuntador –Para bloque de tamaño mayor que “n” Dividir el bloque libre y dar la parte final Espacio libreTSig Espacio ocupadoT Espacio libreTSig ocupadoSigTnlibreT

Compiladores II ( /06/ :10) Pedir Memoria (II) struct bloque { int sz; struct bloque *sig; } *libres; void *malloc(int sz) { struct bloque *p,**ult,*p1; for (p=libres, ult=&libres; p; ult=&(p->sig),p=p->sig) { if (p->sz+sizeof(int)==sz) { *ult=p->Sig; return &p->sig; } else if (p->sz+sizeof(int)+sizeof(struct bloque)>=sz) { p1=(char*) p+sz+sizeof(struct bloque); p1->sz=sz+sizeof(int); p->sz-=sz+sizeof(int); return &p1->sig; } return NULL; }

Compiladores II ( /06/ :10) Liberar Memoria (I) Fragmentación de los bloques libres –Se da al liberar un bloque vecino de bloques libres Fusionar bloques para evitar la fragmentación –Buscar el bloque vecino anterior al bloque a liberar (vecino izquierdo) –Como los bloques están ordenados, el bloque siguiente será el único candidato a vecino derecho. libreTSocupadoTlibreTSocupadoT libreTS T TSocupadoTS libreTSocupadoTlibreTSocupadoT libreTSocupadoT

Compiladores II ( /06/ :10) Liberar Memoria (II) void free(void *address) { struct bloque *p,*ant,*p1; p1=(struct bloque*) ((char*) address-sizeof(int)); for (p=libres, ult=NULL; p && p sig) ; if (ant && (char*) ant+ant->sz+sizeof(int)==address) { /* Juntar con el anterior */ ant->sz+=p1->sz; p1=ant; } else { /* Nuevo bloque libre */ p1->Sig=ant->Sig; ant->Sig=p1; } if ((char*)p1+p1->sz==p1->Sig) { /* Juntar con el bloque siguiente */ p1->sz+=p1->Sig->sz; p1->Sig=p1->Sig->Sig; }

Compiladores II ( /06/ :10) Problemas de la Lista de Bloques Hay que realizar búsquedas por una lista secuencial para: –Pedir memoria –Liberar memoria Hay fragmentación externa de la memoria Soluciones a la búsqueda en la liberación de memoria: –Utilizar listas doblemente encadenadas –Guardar la información del bloque en sus extremos.

Compiladores II ( /06/ :10) Bloques Etiquetados en los Extremos (boundary-tag) Se utiliza una lista doblemente encadenada para guardar los bloques libres. De esta forma se evita buscar el bloque anterior a uno dado cuando hay que eliminarlo de la lista Se guarda la información de los bloques en sus extremos, para poder acceder a ella desde los bloques contiguos. –Bloque libre –Bloque ocupado –F: flag de libre/ocupado –T: tamaño –S: apuntador al siguiente –A: apuntador al anterior Espacio libreFS Espacio ocupadoT ATTF FF

Compiladores II ( /06/ :10) Pedir Memoria Pedir memoria es igual que en el algoritmo anterior –Buscar en la lista de bloques libres un bloque con Tamaño=n bytes+tamaño cabecera bloque ocupado (4bytes) Tamaño>=n+tamaño cabecera bloque libre (16bytes)+tamaño cabecera bloque ocupado (4bytes) –Para bloque de tamaño n Sacarlo de la lista de libres y retornar apuntador –Para bloque de tamaño mayor que “n” Dividir el bloque libre y dar la parte final Diferencias: –La lista de bloques libres es doblemente encadenada –La lista no está ordenada

Compiladores II ( /06/ :10) Liberar Memoria Para evitar la fragmentación hay que fusionar los bloques vecinos libres –Se puede acceder a las cabeceras de los bloques vecinos sin realizar búsquedas Los flags de libre y ocupado son accesibles desde los dos extremos de los bloques En el caso de estar a la derecha de un bloque libre se puede utilizar su tamaño para llegar a su cabecera –Como la lista de bloques libres es doblemente encadenada no hace falta encontrar el bloque anterior en la lista Ventaja –No hay que hacer búsquedas en la liberación libreFSATTFocupadoTFFlibreFSATTF

Compiladores II ( /06/ :10) Overhead en Memoria Consideraciones preliminares –Apuntadores y tamaños de 32bits Lista ordenada de bloques libres –Tamaño mínimo de bloque: Sin cabecera 4 bytes Con cabecera 8 bytes –Tamaño cabecera bloque ocupado 4 bytes Bloques etiquetados –Tamaño mínimo de bloque: Sin cabecera 12 bytes Con cabecera 16 bytes –Tamaño cabecera bloque ocupado 4 bytes –Truco Suponer alineación mínima a 4bytes Guardar los flags de ocupado y libres en los bits bajos del tamaño de bloque

Compiladores II ( /06/ :10) Bloques Compañeros El objetivo de este método es eliminar las búsquedas al perdir y al liberar memoria Idea –Los bloques solo pueden ser de una familia de tamaños: 2 n Bytes –La búsqueda al pedir memoria quedará reducida a un array de listas de bloques libre de 32 posiciones como máximo. Bloque libre Bloque ocupado F: booleano de libre/ocupado C: código A: apuntador al anterior bloque S: apuntador al siguiente bloque T: tamaño del bloque 2 32 Bloques libres Bloques libres Bloques libres Espacio libreSACTF Espacio ocupadoCTF

Compiladores II ( /06/ :10) Pedir Memoria Pedir m bytes –Buscar en la lista de bloques 2 n -TC >=m> 2 n-1 -TC TC: tamaño cabecera –Si no vacía coger el primer bloque de la lista –Si lista vacía buscar en la de tamaño n+1. Si vacia en la n+2, etc. Dividir el bloque y poner uno en la lista de tamaño menor hasta llegar a la lista de tamaño 2 n. 2 n+1 2n2n 2 n+2 2 n+1 2n2n 2 n+2 Después de la división de bloques Antes de la división de bloques

Compiladores II ( /06/ :10) Memoria Desaprovechada Este método sólo se utiliza en sistemas con memoria virtual que permitan reservar espacio de direcciones sin reservar la memoria física. Ejemplo Pedimos 33K –Tamaño página 4K –Tamaño bloque 64K –Memoria desaprovechada 3K –Espacio de direcciones desaprovechado 28K 4K Memoria Pedida 33K Páginas reservadas Físicamente 36K Páginas no reservadas Físicamente 28K

Compiladores II ( /06/ :10) Liberar Memoria Problema: Los bloques fusionados tienen que ser de tamaño potencia de 2. Solución: –Codificación de los bloques compañeros B. raiz: código raíz =código izquierdo -1 B. izquierdo: código izquierdo =código raíz +1 B. derecho: código derecho =0 2n2n 2n2n 2n2n 2n2n 2 n+1 2 n+2 2n2n 2n2n 2n2n 2n2n 2n2n 2 n+1 2n2n 2n2n 2 n n 2 n C=22 n C=02 n C=12 n C=0 2 n+1 C=12 n+1 C=0 2 n+2 C=0 2 n C=22 n C=02 n C=12 n C=0 2 n C=22 n C=02 n C=12 n C=0 2 n C=22 n C=02 n+1 C=0 2 n+1 C=1 2 n+2 C=0

Compiladores II ( /06/ :10) Gestión de Memoria Implícita El gestor se encarga de liberar los bloques de memoria que no utilice el programa. Ventajas –El programador se olvida de la gestión de memoria Reduce los errores Desarrollo rápido Desventajas –Métodos lentos –Desaprovechamiento de la memoria Métodos: –Contadores de referencias –Recolectores Marcar y barrer Recolector por copia Base de los métodos –Un bloque no referenciado por apuntadores no lo utiliza el programa y por lo tanto se puede liberar automáticamente.

Compiladores II ( /06/ :10) Contadores de Referencias Este método se basa en contar el número de apuntadores que referencian cada bloque de memoria Implementación –Cada bloque tiene un contador de referencias y se conocen los apuntadores que contiene. –Cada creación, modificación o destrucción de un apuntador supone actualizar los contadores de los bloques a los que apunta. –Cuando el contador de un bloque llega a cero se libera automáticamente. P1 P2 P3 122 P1 P2 P3 112 P1 P2 P3 003

Compiladores II ( /06/ :10) Contadores de Referencias y Estructuras Cíclicas Los contadores de referencias fallan al liberar estructuras de datos cíclicas Usos –Gestión de objetos del sistema operativo (handlers en windows) –Liberación de objetos en C++ No se usa –Gestor de memoria de un lenguaje –Gestor de memoria genérico P

Compiladores II ( /06/ :10) Recolectores de Memoria Idea básica –El programa pide memoria hasta que no queda. Entonces se activa el recolector de memoria que libera la memoria que no utiliza el programa Necesidades de los recolectores –Tienen que poder recorrer toda la memoria del programa y detectar donde están los apuntadores –Implementación: Usar datos encapsulados en nodos o celdas para facilitar la identificación de los apuntadores en su interior Cada nodo o celda tiene un descriptor de su contenido Los apuntadores que no se encuentren en el heap se considerarán como apuntadores externos y hay algún método para localizarlos.

Compiladores II ( /06/ :10) Marcar y Barrer Este método actúa en dos pasos –Marcar: marca todos los bloques a los que tiene acceso el programa –Barrer: libera los bloques no marcados El heap se divide en nodos o bloques con la siguiente estructura –Descriptor del bloque –Marca –Apuntadores –Otros datos Un bloque libre tiene un descriptor que indica que es libre y los datos que necesite un gestor de memoria explícito para poder pedir bloques (lista de libres). DescriptorMarca Apuntadores Otros datos

Compiladores II ( /06/ :10) Pedir Memoria Al pedir un bloque de memoria se tiene que especificar de que tipo es (descriptor) y su tamaño. Se busca el bloque en una lista de libres y tal como lo podría hacer un gestor de memória explicito Se inicializa el bloque y se retorna al programa En caso que no se encuentre el bloque se activa la recolección de memoria –Marcar –Barrer

Compiladores II ( /06/ :10) Marcar Se siguen las cadenas de apuntadores que empiezan en un apuntador externo (variable local o global, etc). Para todo apuntador externo –P=apuntador externo –*P es un nodo marcado No hacer nada –*P es un nodo por marcar Marcar el nodo Repetir el mismo proceso que se ha realizado con P para todos los apuntadores del nodo Marcar(p) { If (!p->Marca) { p->Marca=true for (q apuntador de *p) Marcar(q); }

Compiladores II ( /06/ :10) Marcar sin Pila Problema: El proceso de marcado anterior es recursivo y puede necesitar mucho espacio de pila, pero resulta que esto no es posible ya que cuando se activa el recolector no queda memoria. Solución: Utilizar los apuntadores ya recorridos como pila –Variables: Act= apuntador al nodo a marcar Ant= pila de nodos marcados pero que no se han seguido sus apuntadores –Push Tmp=Act; Act=Act->Apuntador Tmp->Apuntador=Ant Ant=tmp –Pop Tmp=Act Act=Ant Ant=Ant->Apuntador Act->Apuntador=Tmp

Compiladores II ( /06/ :10) Push/Pop Act Ant Act Ant Act Ant PUSH POP

Compiladores II ( /06/ :10) Barrer Recorrer secuencialmente todo el heap y para cada nodo hacer –Nodo marcado Desmarcar –Nodo NO marcado Liberar Complejidad del método –Marcar Complejidad lineal respecto el número de nodos utilizados por el programa –Barrer Complejidad lineal respecto el número de nodos que hay en el heap (tamaño del heap) –La complejidad más alta corresponde al paso de barrer

Compiladores II ( /06/ :10) Recolección por Copia Idea básica –Divide la memoria en un espacio fuente y uno destino. El programa solo puede utilizar el espacio fuente –Cuando se llena el espacio fuente el recolector copia los nodos utilizados por el programa al espacio destino e invierte los papeles de los dos espacios Libre Ocupado Libre Espacio fuente Espacio destino

Compiladores II ( /06/ :10) Pedir Memoria El apuntador Libre apunta a la primera posición libre del espacio fuente. Pedir(n) { if (Libre+n> Final espacio fuente) Activar recolector(); if (Libre+n<=Final espacio fuente) { p=Libre; Libre=Libre+n; return p; } else Error por falta de memoria } Libre Ocupado Espacio fuente Espacio destino Libre

Compiladores II ( /06/ :10) Recolección Copiar los nodos directamente apuntados por apuntadores externos y sustituir su cabecera por un apuntador al espacio destino donde se encuentra la nueva copia del nodo Recorrer los nodos copiados para copiar los nodos a que estos apunten P1 P P1 P P1 P Heap lleno Copia nodos directamente Apuntados por Apuntadores externos Copia De todos los nodos

Compiladores II ( /06/ :10) Complejidad Recolección por copia –Complejidad lineal respecto a los nodos utilizados por el programa –Al aumentar el tamaño del heap se reduce el número de recolecciones y como estas tienen el mismo coste, el tiempo dedicado a la recolección es menor Marcar y barrer –Complejidad lineal respecto al tamaño del heap –Al aumentar el tamaño del heap se reduce el número de recolecciones, pero estas son más costosas. Por lo tanto, no se “reduce” el tiempo dedicado a la recolección. Se reduce para el marcado, pero no para el barrido