MemoryLayout y alineación
Inspeccione el tamaño, el stride y la alineación de los tipos.
MemoryLayout y alineación es una lección gratuita de Swift Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Swift Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Swift Academy incluye 4 lecciones en total.
Por qué importa la disposición de memoria
Cuando trabaja con unsafe Swift o realiza interoperabilidad con C, necesita saber cómo se organizan los valores en memoria. Swift le proporciona MemoryLayout<T> para inspeccionarlo sin tocar nunca bytes sin procesar.
Responde a tres preguntas: cuánto ocupa un valor, qué distancia hay entre los valores de un array y en qué límite de dirección debe comenzar un valor.
// MemoryLayout works on any type
print(MemoryLayout<Int>.size) // 8 on 64-bit
print(MemoryLayout<Bool>.size) // 1
print(MemoryLayout<Double>.size) // 8size — almacenamiento efectivo
MemoryLayout<T>.size es el número de bytes que ocupan los datos relevantes del valor. No incluye el relleno final que puede existir entre los elementos de un array.
Use size cuando quiera saber cuántos bytes relevantes contiene un único valor.
struct Point {
var x: Int8 // 1 byte
var y: Int64 // 8 bytes
}
print(MemoryLayout<Point>.size) // 16 (not 9 — padding!)stride — separación en arrays
stride es la distancia en bytes entre el inicio de un elemento y el siguiente cuando los valores se almacenan en un array contiguo. Equivale a size redondeado hasta la alineación.
Cuando asigne buffers manualmente, multiplique por stride, nunca por size.
print(MemoryLayout<Point>.stride) // 16
print(MemoryLayout<Int8>.stride) // 1
// Buffer for 10 Points needs:
let bytes = 10 * MemoryLayout<Point>.stride // 160alignment — límites de dirección
alignment es el límite de bytes en el que debe comenzar un valor. Un Int64 con una alineación de 8 debe comenzar en una dirección divisible por 8. El compilador inserta relleno para cumplir esta condición.
La alineación de una estructura es la mayor alineación de sus miembros.
print(MemoryLayout<Int8>.alignment) // 1
print(MemoryLayout<Int64>.alignment) // 8
print(MemoryLayout<Point>.alignment) // 8La diferencia entre size y stride
En muchos tipos, size == stride, pero difieren cuando existe relleno. Una estructura puede tener un size de 9 y, aun así, un stride de 16 porque el siguiente elemento debe estar alineado a 8 bytes.
Regla práctica: use size para razonar sobre un único valor y stride para razonar sobre colecciones.
struct Mixed {
var flag: Bool // 1
var value: Int // 8
}
print(MemoryLayout<Mixed>.size) // 16
print(MemoryLayout<Mixed>.stride) // 16Desplazamientos de campos
En las estructuras, puede consultar dónde se encuentra cada propiedad almacenada con respecto al inicio mediante MemoryLayout<T>.offset(of:) y una key path. Esto es esencial al organizar los datos para que coincidan con una estructura de C.
struct Header {
var magic: UInt32 // offset 0
var length: UInt64 // offset 8 (padded)
}
print(MemoryLayout<Header>.offset(of: \Header.magic) ?? -1) // 0
print(MemoryLayout<Header>.offset(of: \Header.length) ?? -1) // 8Reordenar para ahorrar espacio
Debido a la alineación, el orden de las propiedades almacenadas afecta al tamaño. Colocar primero los campos más grandes o agruparlos por tamaño puede reducir una estructura. Esto es importante en arrays grandes, donde los bytes desperdiciados se acumulan.
struct Wasteful { var a: Int8; var b: Int64; var c: Int8 } // size 24
struct Tight { var b: Int64; var a: Int8; var c: Int8 } // size 16
print(MemoryLayout<Wasteful>.size)
print(MemoryLayout<Tight>.size)Disposición de las referencias
Una instancia de clase se asigna en el montón, por lo que una variable que contiene una referencia a una clase es simplemente un puntero. Su MemoryLayout.size equivale al tamaño del puntero (8 bytes), independientemente del tamaño del objeto.
Los tipos de valor, como las estructuras, almacenan su contenido en línea; los tipos de referencia almacenan únicamente el puntero.
class Big { var data = [Int](repeating: 0, count: 1000) }
print(MemoryLayout<Big>.size) // 8 — just the referenceOpcionales y enumeraciones
Los opcionales suelen añadir un byte para la etiqueta, pero Swift optimiza los opcionales de referencia reutilizando el puntero nulo, por lo que String? puede tener el mismo tamaño que String.
Las enumeraciones con valores asociados tienen el tamaño necesario para contener su caso más grande, además de un discriminador.
print(MemoryLayout<Int?>.size) // 9
print(MemoryLayout<String>.size) // 16
print(MemoryLayout<String?>.size) // 16 — no extra byteUso de of: con una instancia
Cada miembro (size, stride, alignment) también tiene una forma basada en una instancia: MemoryLayout.size(ofValue:). Esto resulta útil cuando es difícil escribir el tipo explícitamente o cuando se infiere.
let tuple = (UInt8(1), UInt64(2))
print(MemoryLayout.size(ofValue: tuple)) // 16
print(MemoryLayout.stride(ofValue: tuple)) // 16
print(MemoryLayout.alignment(ofValue: tuple)) // 8Asignación con la disposición correcta
Al asignar memoria sin procesar, debe indicar tanto el número de bytes como la alineación. Obtener estos valores de MemoryLayout garantiza la corrección en distintas arquitecturas, en lugar de codificar números fijos.
let count = 4
let capacity = count * MemoryLayout<Int>.stride
let align = MemoryLayout<Int>.alignment
let raw = UnsafeMutableRawPointer.allocate(
byteCount: capacity, alignment: align)
defer { raw.deallocate() }Comprobación rápida
Compruebe su comprensión de la diferencia entre size y stride.
Resumen
Ha aprendido los tres pilares de la disposición de memoria:
- size — bytes relevantes de un único valor
- stride — separación entre los elementos de un array (úselo para la asignación)
- alignment — límite de inicio requerido
También ha visto offset(of:) para consultar las posiciones de los campos, cómo el orden de las propiedades afecta al tamaño y que las referencias solo ocupan el tamaño de un puntero. Estas herramientas le permiten asignar e interpretar memoria sin procesar de forma segura.
Preguntas frecuentes
¿La lección «MemoryLayout y alineación» es gratis?
Sí — el texto completo de «MemoryLayout y alineación» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Swift Academy, actualiza a CoddyKit PRO. El curso de Swift Academy incluye 4 lecciones en total.
¿Qué aprenderé en «MemoryLayout y alineación»?
Inspeccione el tamaño, el stride y la alineación de los tipos. Practicas Swift Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Swift Academy?
No se requiere experiencia previa. Swift Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «MemoryLayout y alineación»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Swift Academy?
Sí. Cada lección de Swift Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- MemoryLayout y alineación
- UnsafePointer y UnsafeMutablePointer
- Punteros de búfer inseguros
- withUnsafeBytes e interoperabilidad con C