Gestión de memoria — práctica con problemas guiados paso a paso: traducir con paginación, segmentación con límites, la TLB y un ejercicio con el formato del examen (y la dirección física que di para un segmento que no existía)

En un simulacro de IC2 tenía una tabla de segmentos y tres direcciones lógicas para traducir. Las dos primeras salieron bien. La tercera era ⟨1, 400⟩, con el segmento 1 en la base 6300 y límite 400, y yo sumé sin pensar: 6300 + 400 = 6700. Al corregir, ponía «excepción». El segmento tiene 400 bytes, del desplazamiento 0 al 399, así que el 400 ya está fuera. Mi dirección física apuntaba al primer byte de otro segmento, justo lo que la MMU tiene que impedir. Desde entonces, antes de sumar nada, compruebo.

Esta es la práctica guiada de gestión de memoria. En la teoría de gestión de memoria viste la MMU, la memoria contigua, la segmentación, la paginación y la TLB, con gcc repartido por los marcos del portátil. Aquí resolvemos cuatro problemas paso a paso, como en la parte escrita y en los cálculos del test: traducir direcciones con paginación (en decimal y en hexadecimal), traducir con segmentación comprobando el límite, calcular el tiempo efectivo de acceso con TLB y un ejercicio con el formato del examen (tamaño de la tabla de páginas y los tres ajustes). Después, en los ejercicios de gestión de memoria, te toca a ti.

Antes de empezar

Conviene tener claro:

  • Que 1 KiB son 1024 bytes y que los tamaños de página son potencias de 2.
  • Paginación: dirección lógica = ⟨página, desplazamiento⟩, con página = dirección / tamaño de página (división entera) y desplazamiento = el resto; física = marco × tamaño + desplazamiento.
  • Segmentación: ⟨segmento, desplazamiento⟩; física = base + desplazamiento solo si desplazamiento < límite.
  • La fórmula de la TLB: t=h (T+M)+(1−h) (T+2M) t = h\,(T + M) + (1 – h)\,(T + 2M) .

Si alguno te suena dudoso, repasa la teoría antes de seguir.

Con páginas que son potencia de 2, en hexadecimal no hace falta dividir: los bits bajos son el desplazamiento y los altos, la página. Con 4 KiB (2122^{12}), las tres últimas cifras hexadecimales son el desplazamiento.

Cómo se resuelve un problema de memoria

Los cuatro problemas siguen el mismo método de cuatro pasos:

  1. Pasa los tamaños a bytes (o a potencias de 2) y apunta en qué base viene cada dirección.
  2. Parte la dirección en sus dos campos: página y desplazamiento, o segmento y desplazamiento.
  3. Comprueba y traduce: en segmentación, primero el límite; en paginación, que la página exista en la tabla. Después, sustituye o suma.
  4. Comprueba el resultado: que la física caiga dentro del marco o del segmento correspondiente, y que el desplazamiento no haya cambiado.

Problema 1: traducir con paginación

Enunciado. a) Con páginas de 2 KiB, traduce la dirección lógica 5000 con esta tabla de páginas: página 0 → marco 3, página 1 → marco 11, página 2 → marco 7, página 3 → marco 4. b) Con páginas de 4 KiB, traduce 0x1A3C sabiendo que la página 0 está en el marco 0x2 y la página 1 en el marco 0x5.

La idea

La MMU no suma nada a la dirección lógica: la parte en dos. El desplazamiento dentro de la página pasa tal cual; solo el número de página se sustituye por el número de marco. En decimal se parte dividiendo entre el tamaño de página; en hexadecimal, si la página es 2122^{12}, cortando las tres últimas cifras.

Paso a paso

a) 2 KiB = 2048 bytes.

5000=2⋅2048+904  ⇒  paˊgina 2, desplazamiento 904 5000 = 2 \cdot 2048 + 904 \;\Rightarrow\; \text{página } 2,\ \text{desplazamiento } 904

La página 2 está en el marco 7:

fıˊsica=7⋅2048+904=14336+904=15240 \text{física} = 7 \cdot 2048 + 904 = 14336 + 904 = 15240
Traducir una dirección con paginaciónLa dirección lógica 5000 con páginas de 2048 bytes se parte en página 2 y desplazamiento 904; la tabla dice que la página 2 está en el marco 7, así que la física es 7 por 2048 más 904, 15240.dirección lógica 5000, páginas de 2 KiB (2048 B)página 2desplazamiento 9045000 / 2048 = 2resto 904031112734tabla de páginasfísica = 7 × 2048 + 904 = 15240
La página se sustituye por el marco; el desplazamiento pasa tal cual.

b) 4 KiB = 2122^{12} bytes: los 12 bits bajos (tres cifras hex) son el desplazamiento.

0x1A3C  ⇒  paˊgina 0x1, desplazamiento 0xA3C \mathrm{0x1A3C} \;\Rightarrow\; \text{página } \mathrm{0x1},\ \text{desplazamiento } \mathrm{0xA3C}

La página 1 está en el marco 0x5, así que la física es el marco seguido del mismo desplazamiento: 0x5A3C. Sin multiplicar: en hexadecimal, 5⋅0x1000+0xA3C=0x5A3C5 \cdot \mathrm{0x1000} + \mathrm{0xA3C} = \mathrm{0x5A3C}.

Comprobación

  • a) El desplazamiento tiene que ser menor que el tamaño de página: 904 < 2048. Y la física cae dentro del marco 7, que va de 14336 a 16383.
  • b) Las tres últimas cifras de la física son las mismas que las de la lógica (A3C): el desplazamiento no cambia.
  • En decimal, 0x1A3C = 6716 = 1 · 4096 + 2620, y 0x5A3C = 23100 = 5 · 4096 + 2620: cuadra.

Preguntas que te puedes hacer

¿Por qué no se suma la base, como en la segmentación? Porque las páginas y los marcos tienen el mismo tamaño y están alineados: basta con cambiar el número de página por el de marco. Por eso la paginación es tan barata en hardware.

¿Y si la página no está en la tabla (o su bit de válida es 0)? La MMU lanza una excepción. Si hay memoria virtual, es un fallo de página y el sistema operativo la trae del disco (lo ves en el tema siguiente).

¿Cuántos bits tiene el desplazamiento con páginas de 2 KiB? 11, porque 211=20482^{11} = 2048. En una dirección de 16 bits quedarían 5 para la página: 32 páginas.

¿Por qué el ejemplo de la teoría con 4 KiB daba 2604 de desplazamiento? Porque 4 KiB son 4096 bytes, no 4000. Usar potencias de 10 en lugar de potencias de 2 es el error más caro de este tema.

Tomar 2 KiB como 2000 bytes. Con 5000 saldría página 2 y desplazamiento 1000, y una física de 7 · 2000 + 1000 = 15000: dos números mal.

Pruébalo tú

  • Traduce la dirección lógica 2047 y la 2048 del apartado a). ¿Por qué caen en marcos tan distintos si solo se diferencian en 1?
  • Con páginas de 4 KiB, ¿qué página y qué desplazamiento tiene 0x3FFF?

Problema 2: segmentación con límites

Enunciado. La tabla de segmentos de un proceso es:

SegmentoBaseLímite
0 (código)14001000
1 (pila)6300400
2 (datos)43001100

Traduce las direcciones lógicas ⟨0, 430⟩, ⟨1, 400⟩ y ⟨2, 1099⟩.

La idea

Cada segmento tiene su tamaño (el límite), así que el desplazamiento válido va de 0 a límite − 1. La MMU hace siempre lo mismo y en este orden: comprueba que el desplazamiento es menor que el límite y, solo si lo es, suma la base. Si no, excepción y el proceso no accede a nada.

Paso a paso

Dirección¿Desplazamiento < límite?Física
⟨0, 430⟩430 < 1000: sí1400 + 430 = 1830
⟨1, 400⟩400 < 400: noexcepción
⟨2, 1099⟩1099 < 1100: sí4300 + 1099 = 5399

Comprobación

  • 1830 está entre 1400 y 2399 (el segmento 0). 5399 está entre 4300 y 5399: es justo el último byte del segmento 2.
  • ⟨1, 400⟩ daría 6700, que ya no es del segmento 1 (que acaba en 6699).

Preguntas que te puedes hacer

¿Por qué 1099 vale y 400 no, si los dos son «el tamaño menos algo»? Porque el límite del segmento 2 es 1100 (1099 es el último válido) y el del segmento 1 es 400 (el último válido es 399). La comparación es siempre estricta: menor que el límite.

¿Qué pasaría si la MMU sumara primero y comprobara después? Daría el mismo resultado en las direcciones válidas, pero comprobar sobre la física es más difícil (habría que conocer el final de cada segmento en memoria). Comprobar el desplazamiento contra el límite es una sola comparación.

¿Los segmentos pueden estar en cualquier orden en la RAM? Sí: el 0 en 1400, el 2 en 4300 y el 1 en 6300. Cada uno es un bloque contiguo, pero el proceso no necesita estar entero junto. Por eso la segmentación sufre fragmentación externa.

¿Y si el segmento no existe (⟨3, 10⟩)? El número de segmento se compara con el tamaño de la tabla: si es mayor, también hay excepción.

Sumar la base sin comprobar el límite, o comprobar con «≤». En el examen, una dirección inválida con su física calculada está mal aunque la suma esté bien.

Pruébalo tú

  • Traduce ⟨0, 999⟩, ⟨0, 1000⟩ y ⟨2, 0⟩.
  • ¿Qué límite mínimo tendría que tener el segmento 1 para que ⟨1, 400⟩ fuera válida?

Problema 3: la TLB y el tiempo efectivo de acceso

Enunciado. Un sistema paginado tiene una TLB de 5 ns y una memoria de 80 ns. a) Calcula el tiempo efectivo de acceso con una tasa de aciertos del 90 % y del 98 %. b) ¿Cuánto tardaría sin TLB? c) ¿Y con una tabla de dos niveles y el 90 % de aciertos?

La idea

Cada acceso pasa siempre por la TLB. Si acierta, ya tenemos el marco y solo falta leer el dato: un acceso a memoria. Si falla, hay que leer la entrada de la tabla de páginas en memoria y después el dato: dos accesos (con una tabla de dos niveles, tres). El tiempo efectivo es la media ponderada.

Paso a paso

Tiempo efectivo de acceso con TLBCada acceso pasa por la TLB (5 ns): con acierto, un acceso a la RAM (85 ns en total); con fallo, dos (165 ns). Con un 90 % de aciertos sale 93 ns de media.CPUTLB · 5 nsacierto (90 %)RAM: el dato · 80 ns5 + 80 = 85 nsfallo (10 %)RAM: tabla + dato · 2 × 80 ns5 + 160 = 165 ns0,9 · 85 + 0,1 · 165 = 76,5 + 16,5 = 93 ns
El fallo de TLB cuesta un acceso más a la RAM: el de la tabla de páginas.

a) Con acierto: 5+80=855 + 80 = 85 ns. Con fallo: 5+2⋅80=1655 + 2 \cdot 80 = 165 ns.

h=0,9:t=0,9⋅85+0,1⋅165=76,5+16,5=93 ns h = 0{,}9:\quad t = 0{,}9 \cdot 85 + 0{,}1 \cdot 165 = 76{,}5 + 16{,}5 = 93 \text{ ns}
h=0,98:t=0,98⋅85+0,02⋅165=83,3+3,3=86,6 ns h = 0{,}98:\quad t = 0{,}98 \cdot 85 + 0{,}02 \cdot 165 = 83{,}3 + 3{,}3 = 86{,}6 \text{ ns}

b) Sin TLB, cada acceso son dos accesos a memoria: 2⋅80=1602 \cdot 80 = 160 ns. La TLB al 90 % lo deja en 93: casi la mitad.

c) Con dos niveles, un fallo de TLB cuesta tres accesos (dos entradas de tabla y el dato): 5+3⋅80=2455 + 3 \cdot 80 = 245 ns.

t=0,9⋅85+0,1⋅245=76,5+24,5=101 ns t = 0{,}9 \cdot 85 + 0{,}1 \cdot 245 = 76{,}5 + 24{,}5 = 101 \text{ ns}

Comprobación

  • El resultado tiene que estar entre el caso de acierto (85) y el de fallo (165): 93 y 86,6 lo están.
  • Al subir la tasa de aciertos, el tiempo baja hacia 85: con el 100 % sería 85 exactos.
  • Con dos niveles solo cambia el coste del fallo; el acierto sigue costando 85.

Preguntas que te puedes hacer

¿Por qué se suma la TLB también en el fallo? Porque la TLB se consulta siempre primero: solo después de fallar se va a la tabla. Hay diseños que consultan en paralelo, pero en el tema (y en el examen) se suma.

¿Por qué la TLB funciona con tan pocas entradas? Por la localidad: en un intervalo corto, el programa usa pocas páginas, y la TLB guarda justo esas.

¿Qué pesa más, mejorar la TLB de 5 a 2 ns o subir los aciertos del 90 al 98 %? Con 2 ns y el 90 %: 0,9⋅82+0,1⋅162=900{,}9 \cdot 82 + 0{,}1 \cdot 162 = 90 ns. Subir aciertos da 86,6: en este sistema compensa más acertar que ser rápido.

¿Esto es lo mismo que el tiempo efectivo con fallos de página? Es la misma idea de media ponderada, pero con números muy distintos: un fallo de página cuesta milisegundos. Lo ves en el tema siguiente.

Poner en el fallo de TLB un solo acceso a memoria (olvidando la tabla) o no sumar la TLB en el acierto. Escribe siempre los dos caminos antes de ponderar.

Pruébalo tú

  • ¿Qué tasa de aciertos hace falta para que el tiempo efectivo sea 90 ns con la TLB de 5 ns?
  • Repite el apartado c) con una tabla de tres niveles.

Problema 4: un ejercicio con el formato del examen

En la parte escrita y en los cálculos del test de IC2 aparecen el tamaño de la tabla de páginas y la asignación de memoria contigua con primer, mejor y peor ajuste. Se valora que se vean las cuentas y el estado de los huecos después de cada asignación. Este ejercicio es original y está escrito con ese formato.

Ejercicio. a) Un sistema tiene direcciones lógicas de 32 bits, páginas de 8 KiB y entradas de tabla de 4 bytes. ¿Cuántas entradas tiene la tabla de páginas de un proceso y cuánto ocupa? b) La memoria tiene huecos de 150, 400, 220, 500 y 120 KiB, en ese orden. Llegan, por este orden, los procesos A (180 KiB), B (350 KiB), C (90 KiB) y D (420 KiB). Indica en qué hueco va cada uno con primer ajuste, mejor ajuste y peor ajuste.

ProcesoPrimer ajusteMejor ajustePeor ajuste
A (180)_________
B (350)_________
C (90)_________
D (420)_________

La idea

a) El desplazamiento ocupa los bits que hacen falta para recorrer una página y el resto son bits de página: cada combinación es una entrada. b) Para cada proceso, por orden, se mira la lista de huecos tal como ha quedado después del anterior: primer ajuste coge el primero que cabe, mejor ajuste el más pequeño que cabe y peor ajuste el más grande.

Paso a paso

a) 8 KiB = 2132^{13} bytes: 13 bits de desplazamiento, así que quedan 32−13=1932 – 13 = 19 bits de página.

219=524 288 entradas219⋅4 B=221 B=2 MiB 2^{19} = 524\,288 \text{ entradas} \qquad 2^{19} \cdot 4 \text{ B} = 2^{21} \text{ B} = 2 \text{ MiB}

b) Huecos iniciales: 150, 400, 220, 500 y 120.

Primer ajuste: A (180) no cabe en 150; va al 400 (quedan 220). B (350): 150 no, 220 no, 220 no, 500 (quedan 150). C (90): cabe en el primero, 150 (quedan 60). D (420): ningún hueco llega a 420 (60, 220, 220, 150, 120): espera.

Mejor ajuste: A (180): los que caben son 400, 220 y 500; el más pequeño, 220 (quedan 40). B (350): 400 y 500; el 400 (quedan 50). C (90): caben 150, 500 y 120; el 120 (quedan 30). D (420): el 500 (quedan 80).

Peor ajuste: A (180): el más grande, 500 (quedan 320). B (350): el 400 (quedan 50). C (90): el más grande ahora es el de 320, que era el 500 (quedan 230). D (420): ningún hueco llega (150, 50, 220, 230, 120): espera.

ProcesoPrimer ajusteMejor ajustePeor ajuste
A (180)400220500
B (350)500400400
C (90)150120500
D (420)espera500espera

Comprobación y cómo se corrige

  • a) Comprueba con la otra cuenta: 2322^{32} bytes de espacio lógico entre 2132^{13} por página da 2192^{19} páginas.
  • b) Después de cada asignación, escribe la lista de huecos completa. Si un hueco se usa dos veces (como el de 500 en el peor ajuste), tiene que tener sitio para los dos: 500 − 180 = 320 ≥ 90.

Se valora que se vean los bits de cada campo en a) y el estado de los huecos tras cada proceso en b). Aquí, curiosamente, el mejor ajuste es el único que coloca a los cuatro: el primer y el peor ajuste rompen el hueco grande demasiado pronto.

Decidir cada proceso con la lista de huecos inicial en lugar de con la que dejó el anterior. Con el peor ajuste, C iría al 500 «original» y no al hueco de 320 que quedó.

Pruébalo tú

  • Repite el apartado a) con páginas de 4 KiB y entradas de 8 bytes.
  • Con primer ajuste, ¿en qué orden tendrían que llegar los procesos para que entraran los cuatro?

Errores típicos en esta práctica

  • Usar potencias de 10: 1 KiB son 1024 bytes, no 1000.
  • Sumar en la paginación: la página se sustituye por el marco; el desplazamiento no cambia.
  • No comprobar el límite del segmento, o comprobar con «≤».
  • Olvidar la TLB en el camino del fallo, o el acceso a la tabla.
  • Usar la lista de huecos inicial en todos los procesos en lugar de la que va quedando.
  • No comprobar que la física cae dentro de su marco o de su segmento.

Compruébalo con Python

Este programa hace las cuentas de los cuatro problemas. La función pagina() es la división de la MMU, y ajuste() va gastando los huecos para cada proceso con las tres reglas.

# Gestión de memoria de papel: paginación, segmentación, TLB, tamaño de la tabla y ajustes.
KiB = 1024
def pagina(dl, tam, tabla):
    p, d = divmod(dl, tam)                    # página = cociente, desplazamiento = resto
    return p, d, tabla[p] * tam + d
print("paginación 2 KiB, 5000:", pagina(5000, 2 * KiB, {0: 3, 1: 11, 2: 7, 3: 4}))
p, d, f = pagina(0x1A3C, 4 * KiB, {0: 0x2, 1: 0x5})
print(f"paginación 4 KiB, 0x1A3C: página {p}, desplazamiento {d:#05x}, física {f:#06x}")

segs = {0: (1400, 1000), 1: (6300, 400), 2: (4300, 1100)}   # segmento: (base, límite)
for s, d in ((0, 430), (1, 400), (2, 1099)):
    base, lim = segs[s]
    print(f"segmento ⟨{s}, {d}⟩:", base + d if d < lim else "excepción (desplazamiento >= límite)")

T, M = 5, 80                                   # ns de la TLB y de la RAM
for h in (0.9, 0.98):
    print(f"TLB h={h}: {h * (T + M) + (1 - h) * (T + 2 * M):.1f} ns")
print(f"sin TLB: {2 * M} ns; dos niveles, h=0.9: {0.9 * (T + M) + 0.1 * (T + 3 * M):.1f} ns")

bits, pag, ent = 32, 8 * KiB, 4
n = 2 ** (bits - pag.bit_length() + 1)         # entradas = 2^(bits de dirección - bits de desplazamiento)
print(f"tabla: 2^{bits - pag.bit_length() + 1} = {n} entradas x {ent} B = {n * ent // (1024 * 1024)} MiB")

def ajuste(huecos, procs, regla):
    h, out = list(huecos), []
    for nom, t in procs:
        ok = [i for i, x in enumerate(h) if x >= t]
        if not ok: out.append(f"{nom}: espera"); continue
        i = {"primer": ok[0], "mejor": min(ok, key=lambda i: h[i]), "peor": max(ok, key=lambda i: h[i])}[regla]
        out.append(f"{nom}->{huecos[i]}"); h[i] -= t
    return out, h
for regla in ("primer", "mejor", "peor"):
    print(regla, *ajuste([150, 400, 220, 500, 120], [("A", 180), ("B", 350), ("C", 90), ("D", 420)], regla))

Salida (ejecutado una vez):

paginación 2 KiB, 5000: (2, 904, 15240)
paginación 4 KiB, 0x1A3C: página 1, desplazamiento 0xa3c, física 0x5a3c
segmento ⟨0, 430⟩: 1830
segmento ⟨1, 400⟩: excepción (desplazamiento >= límite)
segmento ⟨2, 1099⟩: 5399
TLB h=0.9: 93.0 ns
TLB h=0.98: 86.6 ns
sin TLB: 160 ns; dos niveles, h=0.9: 101.0 ns
tabla: 2^19 = 524288 entradas x 4 B = 2 MiB
primer ['A->400', 'B->500', 'C->150', 'D: espera'] [60, 220, 220, 150, 120]
mejor ['A->220', 'B->400', 'C->120', 'D->500'] [150, 50, 40, 80, 30]
peor ['A->500', 'B->400', 'C->500', 'D: espera'] [150, 50, 220, 230, 120]

Cosas que observar:

  1. divmod(dl, tam) da a la vez la página (cociente) y el desplazamiento (resto): es todo lo que hace la MMU antes de mirar la tabla.
  2. En el apartado b) del Problema 1, Python escribe los números en hexadecimal con :#05x y :#06x: el desplazamiento 0xa3c aparece igual en la lógica y en la física.
  3. La segunda dirección de segmentación sale como excepción porque la condición es d < lim, estricta.
  4. En ajuste(), la lista h va restando lo asignado; al final se imprime cómo quedan los huecos con cada regla.

Si quieres ver la memoria virtual de este mismo proceso, tienes el siguiente tema: memoria virtual y reemplazo de páginas.

Resumen

  • Paginación: dividir entre el tamaño de página, cambiar la página por el marco, dejar el desplazamiento.
  • En hexadecimal y con páginas de 2122^{12}, las tres últimas cifras son el desplazamiento.
  • Segmentación: comprobar desplazamiento < límite y, solo entonces, sumar la base.
  • TLB: t=h (T+M)+(1−h) (T+2M) t = h\,(T + M) + (1 – h)\,(T + 2M) ; con más niveles, más accesos en el fallo.
  • Tabla de páginas: 2bits de paˊgina2^{\text{bits de página}} entradas por el tamaño de cada una.
  • Ajustes: cada proceso con los huecos que quedaron; el mejor ajuste no siempre deja más sitio, pero aquí coloca a todos.

Checklist: ¿lo has practicado?

  • ¿Has hecho los cuatro problemas en papel antes de leer el paso a paso?
  • ¿Sabes partir una dirección en decimal y en hexadecimal?
  • ¿Compruebas el límite antes de sumar la base?
  • ¿Puedes escribir los dos caminos de la TLB y ponderarlos?
  • ¿Has comprobado los problemas con el programa de Python?
  • ¿Has intentado los «Pruébalo tú» sin mirar la teoría?

Si has respondido que sí a casi todo, estás listo para los ejercicios de gestión de memoria, con un test de todo el tema y cálculos con casillas que se corrigen solas. ¡Nos vemos allí!

Siguiente paso: ejerciciosGestión de memoria — ejercicios tipo examen con direcciones que traducir, una TLB que acierta y huecos que no alcanzan (y el medio nanosegundo que perdí por no sumar la TLB)

¿Te ha servido este artículo? Así puedes apoyar SergioLearns →