netty/netty · error · IllegalArgumentException

directMemoryCacheAlignment: {} (expected: power of two)

Error message

directMemoryCacheAlignment: {} (expected: power of two)

What it means

Thrown by the PooledByteBufAllocator constructor when directMemoryCacheAlignment is not a power of two. The test (alignment & -alignment) != alignment isolates the lowest set bit; equality holds only for powers of two. It is an IllegalArgumentException: the allocator aligns buffer addresses via bit-masking, which requires a single-bit alignment value.

Source

Thrown at buffer/src/main/java/io/netty/buffer/PooledByteBufAllocator.java:300

                        "Either Unsafe or ByteBuffer.alignSlice() must be available.");
            }

            // Ensure page size is a whole multiple of the alignment, or bump it to the next whole multiple.
            pageSize = (int) PlatformDependent.align(pageSize, directMemoryCacheAlignment);
        }

        chunkSize = validateAndCalculateChunkSize(pageSize, maxOrder);

        checkPositiveOrZero(nHeapArena, "nHeapArena");
        checkPositiveOrZero(nDirectArena, "nDirectArena");

        checkPositiveOrZero(directMemoryCacheAlignment, "directMemoryCacheAlignment");
        if (directMemoryCacheAlignment > 0 && !isDirectMemoryCacheAlignmentSupported()) {
            throw new IllegalArgumentException("directMemoryCacheAlignment is not supported");
        }

        if ((directMemoryCacheAlignment & -directMemoryCacheAlignment) != directMemoryCacheAlignment) {
            throw new IllegalArgumentException("directMemoryCacheAlignment: "
                    + directMemoryCacheAlignment + " (expected: power of two)");
        }

        int pageShifts = validateAndCalculatePageShifts(pageSize, directMemoryCacheAlignment);

        if (nHeapArena > 0) {
            heapArenas = newArenaArray(nHeapArena);
            List<PoolArenaMetric> metrics = new ArrayList<PoolArenaMetric>(heapArenas.length);
            final SizeClasses sizeClasses = new SizeClasses(pageSize, pageShifts, chunkSize, 0);
            for (int i = 0; i < heapArenas.length; i ++) {
                PoolArena.HeapArena arena = new PoolArena.HeapArena(this, sizeClasses);
                heapArenas[i] = arena;
                metrics.add(arena);
            }
            heapArenaMetrics = Collections.unmodifiableList(metrics);
        } else {
            heapArenas = null;
            heapArenaMetrics = Collections.emptyList();

View on GitHub (pinned to 70040aacae)

Solutions

  1. Use a power of two: 1, 2, 4, 8, 16, 32, 64, 128 (64 is typical for cache lines).
  2. Round up: alignment = Integer.highestOneBit(requested - 1) << 1; then guard against 0.
  3. If alignment is unnecessary, set it to 0.

Example fix

// before
new PooledByteBufAllocator(true, nHeap, nDirect, pageSize, maxOrder, small, normal, true, 48);

// after
int alignment = Integer.highestOneBit(requestedLine - 1) << 1; // 48 -> 64
new PooledByteBufAllocator(true, nHeap, nDirect, pageSize, maxOrder, small, normal, true, alignment);
Defensive patterns

Strategy: validation

Validate before calling

static int pow2Alignment(int requested) {
    if (requested <= 0) return 0;
    int p = Integer.highestOneBit(requested - 1) << 1;
    return p < 1 ? 1 : p;
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Passing a directMemoryCacheAlignment such as 3, 6, 12, 24, 48 — non-powers of two that a developer picked from a CPU cache-line intuition without converting to the nearest power of two.

Common situations: Using the literal L1/L2 cache line size (e.g. 48 or 96 bytes on some CPUs) instead of rounding to 32/64/128; mirroring a C struct alignment value that is not a power of two.

Related errors


AI-assisted analysis of netty/netty@70040aacae (2026-08-14). Data as JSON: /api/errors/fde44705db9185a1. Report an issue: GitHub.