> ## Content Index
> Fetch the complete content index at: https://huizhou92.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Swiss Map in Go 1.24: Compatibility, Extendible Hashing, and Legacy Issues
- URL: https://huizhou92.com/swiss-map-in-go-124-compatibility-extendible-hashing-and-legacy-issues/
- Published: 2025-01-23T06:34:27.000Z
- Updated: 2026-09-06T11:39:43.000Z
- Description: Explore the groundbreaking Swiss Map in Go 1.24, which offers over 50% performance improvement and seamless migration from legacy maps. Discover the benefits of Extensible Hashing and its innovative design while addressing challenges like concurrency and memory efficiency. Is it time to adopt Swiss…
- Author: huizhou92
- Tags: tech, SwissTable, golang, go, #lang-en

In the [previous article](https://pub.huizhou92.com/swisstable-a-high-performance-hash-table-implementation-3e13bfe8c79b?ref=huizhou92.com), I introduced `swiss map` and a Go implementation by Dolthub. Readers unfamiliar with `swiss map` should review that piece first.

With the upcoming release of Go 1.24, `swiss map` will replace the existing `map` implementation in the Go standard library. It maintains full API compatibility while delivering over 50% performance improvements in specific benchmark scenarios.  
Currently, `swiss map` is my most anticipated feature in Go 1.24\. But does it truly live up to the hype? This article analyzes its core design through three lenses: **compatibility**, **Extensible Hashing implementation**, and **remaining challenges**.

### Compatibility: Seamless Migration Support

One of `swiss map`'s key design goals is backward compatibility with Go's legacy `map`. Conditional compilation flags and type conversions enable zero-code migration. For example, in `export_swiss_test.go`, the `newTestMapType` function directly converts legacy `map` metadata into `swiss map`'s type structure:

```go
// https://github.com/golang/go/blob/3f4164f508b8148eb526fc096884dba2609f5835/src/internal/runtime/maps/export_swiss_test.go#L14
func newTestMapType[K comparable, V any]() *abi.SwissMapType {
    var m map[K]V
    mTyp := abi.TypeOf(m)
    mt := (*abi.SwissMapType)(unsafe.Pointer(mTyp)) // Direct type conversion
    return mt
}

```

This design allows existing code to enable `swiss map` via the experimental flag `GOEXPERIMENT=swissmap` (now enabled by default in gotip builds like `go1.24-3f4164f5`).  
To revert to the legacy map implementation, use `GOEXPERIMENT=noswissmap`.

### Swiss Map's Data Structure

![](https://images.hxzhouh.com/blog-images/2025/01/784e3f6a0ff90601480a2da80f3cb9d0.png)

### Extendible Hashing: Efficient Incremental Scaling

Beyond compatibility improvements, `swiss map` introduces **Extensible Hashing** to enable efficient incremental scaling. Unlike traditional hash tables, which require complete data migration during resizing, Extensible Hashing distributes scaling costs across multiple operations using multi-level directories and table splitting.

#### Directory and Table Hierarchy

The `Map` struct in `map.go` uses `globalDepth` and `directory` to manage hierarchy:

```go
// https://github.com/golang/go/blob/3f4164f508b8148eb526fc096884dba2609f5835/src/internal/runtime/maps/map.go#L194
type Map struct {
    globalDepth  uint8       // Global depth of directory
    dirPtr       unsafe.Pointer // Pointer to directory (array of tables)
    // ...
}

```

The directory size is `1 << globalDepth`, with each entry pointing to a `table`. When a table reaches its capacity (`maxTableCapacity`, default 1024), it triggers a **split** instead of global resizing.

#### Split Operation

A split creates two child tables (`left` and `right`) with increased `localDepth`, redistributing data based on hash bits:

```go
// https://github.com/golang/go/blob/3f4164f508b8148eb526fc096884dba2609f5835/src/internal/runtime/maps/table.go#L1043
func (t *table) split(typ *abi.SwissMapType, m *Map) {
    localDepth := t.localDepth
    localDepth++ // Child tables have +1 local depth
    left := newTable(typ, maxTableCapacity, -1, localDepth)
    right := newTable(typ, maxTableCapacity, -1, localDepth)
    // ...
}

```

New tables allocate contiguous memory blocks via `newarray`, preserving cache locality.

#### Data Redistribution: Hash Masking

During splits, hash values' high-order bits (determined by `localDepth`) dictate data placement:

```go
// https://github.com/golang/go/blob/3f4164f508b8148eb526fc096884dba2609f5835/src/internal/runtime/maps/table.go#L1052
mask := localDepthMask(localDepth) // e.g., 0x80000000 (32-bit)
for ... {
    hash := typ.Hasher(key, m.seed)
    if hash & mask == 0 {
        left.uncheckedPutSlot(...) // Assign to left table
    } else {
        right.uncheckedPutSlot(...) // Assign to right table
    }
}

```

- **Mask Calculation**: `localDepthMask` generates masks like:  
  - `localDepth=1` → `0x80000000` (32-bit) or `0x8000000000000000` (64-bit)

#### Directory Expansion

When a split occurs at the global depth, the directory doubles in size:

```go
// map.go
func (m *Map) installTableSplit(old, left, right *table) {
    if old.localDepth == m.globalDepth {
        newDir := make([]*table, m.dirLen*2) // Double directory size
        // Update directory entries...
        m.globalDepth++
    }
    // ...
}

```

**Example: Directory Expansion**  
Initial state (`globalDepth=1`):

```golang
directory[0] → Table A (localDepth=1)
directory[1] → Table A (localDepth=1)

```

After split (`globalDepth=2`):

```golang
directory[0] → Left  (hash prefix 00)
directory[1] → Left  (hash prefix 01)
directory[2] → Right (hash prefix 10)
directory[3] → Right (hash prefix 11)

```

#### Key Advantages

1. **Locality**: Only overloaded tables split
2. **Incremental Scaling**: Directory grows on demand
3. **Cache Efficiency**: Continuous memory allocation for table groups

### Additional Optimizations

`swiss map` optimizes small-element scenarios (≤8 elements) using a single group, minimizing performance penalties for small datasets.

### Remaining Challenges

Despite significant improvements, several issues remain:

#### Concurrency Limitations

The current implementation uses a simple `writing` flag for concurrent write detection:

```go
// https://github.com/golang/go/blob/3f4164f508b8148eb526fc096884dba2609f5835/src/internal/runtime/maps/map.go#L478
func (m *Map) PutSlot(typ *abi.SwissMapType, key unsafe.Pointer) unsafe.Pointer {
    m.writing ^= 1 // Non-atomic flag
    // ...
}

```

This may cause race conditions in high-concurrency scenarios. Future versions may introduce finer-grained locking.

#### Memory Fragmentation

The `group` structure (8 control bytes + 8 key-value slots) may waste memory for small types. For example, `int32` keys with `int8` values leave 3 bytes unused per slot.

#### Iterator Complexity

The `Iter` implementation handles directory expansion and table splits, adding complexity:

```go
// https://github.com/golang/go/blob/3f4164f508b8148eb526fc096884dba2609f5835/src/internal/runtime/maps/table.go#L742
func (it *Iter) Next() {
    if it.globalDepth != it.m.globalDepth {
        // Handle directory expansion
        it.dirIdx <<= (it.m.globalDepth - it.globalDepth)
    }
    // ...
}

```

Frequent resizing may impact iterator performance.

Additionally, numerous TODOs remain in the latest codebase (see the image below), and questions about their resolution remain unresolved before Go 1.24's release.  
![](https://images.hxzhouh.com/blog-images/2025/01/715d866b7013c977454d49537e01888b.png)

Community discussions highlight performance variability, with some reports of regressions.  
[https://x.com/valyala/status/1879988053076504761](https://x.com/valyala/status/1879988053076504761?ref=huizhou92.com)

### Performance Testing

Test code: [github.com/hxzhouh/gomapbench](https://github.com/hxzhouh/gomapbench?ref=huizhou92.com)  
Environment: `go version devel go1.24-3f4164f5 Mon Jan 20 09:25:11 2025 -0800 darwin/arm64`

![](https://images.hxzhouh.com/blog-images/2025/01/f4a1ee763ddd58e309055e616b562268.png)

Average performance improvements hover around 20%, with some scenarios showing up to 50% gains. However, these results are machine-specific, and some users report performance regressions. The final evaluation awaits further optimization.

### Conclusion

Go 1.24's `swiss map` delivers significant performance gains through compatibility design, Extendible Hashing, and optimized probing sequences. However, challenges remain in concurrency handling and memory efficiency. Developers should consider adopting it in performance-critical contexts while monitoring its evolving implementation.

### References

- [Tony Bai's Analysis](https://tonybai.com/2024/11/14/go-map-use-swiss-table/?ref=huizhou92.com)
- [GitHub Issue #54766](https://github.com/golang/go/issues/54766?ref=huizhou92.com)
- [Extendible Hashing Explained](https://www.geeksforgeeks.org/extendible-hashing-dynamic-approach-to-dbms/?ref=huizhou92.com)
- [Original Implementation Article](https://pub.huizhou92.com/swisstable-a-high-performance-hash-table-implementation-3e13bfe8c79b?ref=huizhou92.com)

---

- Long Time Link
- If you find my blog helpful, please subscribe to me via [RSS](https://huizhou92.com/sitemap.xml)
- Or follow me on [X](https://x.com/@piaopiaopig?ref=huizhou92.com)
- If you have a [Medium](https://medium.huizhou92.com/?ref=huizhou92.com) account, follow me there. My articles will be published there as soon as possible.