Skip to content

Array Padding

Insert unused space between array elements or groups to control alignment and reduce interference.

Array padding inserts unused bytes between elements or groups of elements. It adjusts layout to satisfy alignment constraints or to avoid contention such as false sharing.

You use it when memory layout affects performance or correctness in concurrent settings.

Problem

Given elements of size ss and required alignment or spacing pp, place elements so that consecutive elements are separated by a stride:

strides stride \ge s

and often:

stridemodp=0 stride \bmod p = 0

Structure

A padded array uses a stride larger than the element size.

Logical index ii maps to:

address(A[i])=base(A)+istride address(A[i]) = base(A) + i \cdot stride

Unused bytes in each stride form padding.

Algorithm

Compute padded addresses and access elements.

address(base, stride, i):
    return base + i * stride

Access with padding:

get(A, base, stride, i):
    if i < 0 or i >= length(A):
        error "index out of bounds"

    p = base + i * stride
    return load(p)

Example

Suppose:

fieldvalue
element size8 bytes
desired spacing64 bytes

Then:

stride=64 stride = 64

Addresses:

indexaddress
0base
1base + 64
2base + 128
3base + 192

Each element occupies 8 bytes, with 56 bytes of padding.

Correctness

Each logical index maps to a unique physical region starting at base+istridebase + i \cdot stride. Since stridesstride \ge s, the memory regions for distinct indices do not overlap.

Therefore, reading or writing at index ii accesses only that element’s storage.

Complexity

operationtime
getO(1)O(1)
setO(1)O(1)

Space usage:

O(nstride) O(n \cdot stride)

which may be significantly larger than O(ns)O(n \cdot s).

When to Use

Array padding is appropriate when:

  • alignment requirements must be enforced
  • avoiding false sharing between threads
  • improving cache line utilization for independent data
  • interfacing with hardware or SIMD requirements

It is less suitable when:

  • memory usage must be minimal
  • large padding wastes too much space
  • data is accessed sequentially and compact layout is preferable

Implementation

class PaddedArray:
    def __init__(self, n, stride):
        self.n = n
        self.stride = stride
        self.data = bytearray(n * stride)

    def address(self, i):
        if i < 0 or i >= self.n:
            raise IndexError("index out of bounds")
        return i * self.stride

    def get_bytes(self, i, size):
        p = self.address(i)
        return self.data[p:p+size]

    def set_bytes(self, i, value_bytes):
        p = self.address(i)
        self.data[p:p+len(value_bytes)] = value_bytes
type PaddedArray struct {
    data   []byte
    stride int
    n      int
}

func NewPaddedArray(n, stride int) *PaddedArray {
    return &PaddedArray{
        data:   make([]byte, n*stride),
        stride: stride,
        n:      n,
    }
}

func (p *PaddedArray) address(i int) (int, bool) {
    if i < 0 || i >= p.n {
        return 0, false
    }
    return i * p.stride, true
}

func (p *PaddedArray) Get(i int, size int) ([]byte, bool) {
    addr, ok := p.address(i)
    if !ok {
        return nil, false
    }
    return p.data[addr : addr+size], true
}

func (p *PaddedArray) Set(i int, value []byte) bool {
    addr, ok := p.address(i)
    if !ok {
        return false
    }
    copy(p.data[addr:], value)
    return true
}