# RogueMap
**Repository Path**: bryan31/RogueMap
## Basic Information
- **Project Name**: RogueMap
- **Description**: RogueMap 是一个高性能的嵌入式键值存储引擎,突破 HashMap 的内存墙,提供堆外内存和持久化存储能力。
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: https://roguemap.yomahub.com/
- **GVP Project**: No
## Statistics
- **Stars**: 40
- **Forks**: 7
- **Created**: 2025-12-11
- **Last Updated**: 2025-12-14
## Categories & Tags
**Categories**: cache-modules
**Tags**: None
## README
RogueMap
[](LICENSE)
[](https://www.oracle.com/java/)
[](https://github.com/bryan31/RogueMap)
**RogueMap** 是一个高性能的嵌入式键值存储引擎,突破 HashMap 的内存墙,提供堆外内存和持久化存储能力。
## 🎯 为什么选择 RogueMap?
### HashMap 的困境
在处理大规模数据时,传统的 HashMap 面临诸多限制:
- ❌ **内存瓶颈** - 所有数据必须存储在堆内存,受 JVM 堆大小限制
- ❌ **GC 压力** - 百万级对象导致 Full GC 频繁,影响应用稳定性
- ❌ **数据易失** - 进程重启后数据全部丢失,无持久化能力
- ❌ **容量受限** - 超大数据集(10GB+)无法处理,OutOfMemoryError 噩梦
- ❌ **冷启动慢** - 每次启动都需要重新加载数据,耗时数分钟甚至更久
### RogueMap 的突破
RogueMap 将数据存储在 **堆外内存** 或 **内存映射文件** 中,让你享受 HashMap 的简单 API,同时获得超越其限制的能力:
- ✅ **无限容量** - 突破 JVM 堆限制,轻松处理 100GB+ 数据集
- ✅ **零 GC 压力** - 堆内存占用减少 **87%**,告别 Full GC 噩梦
- ✅ **数据持久化** - 进程重启后数据自动恢复,零成本持久化
- ✅ **即开即用** - Mmap 模式秒级启动,无需预热加载
- ✅ **更快性能** - 读性能比 HashMap 提升 **2.4 倍**,写性能持平
- ✅ **临时存储** - 支持自动清理的临时文件模式,完美替代磁盘缓存
### 核心优势
| 特性 | HashMap | RogueMap |
|------|---------|----------|
| **数据容量** | 受限于堆大小(通常 < 10GB) | **无限制**,可达 TB 级 |
| **堆内存占用** | 100% | **仅 13%** |
| **GC 影响** | 严重(Full GC 秒级) | **几乎无影响** |
| **持久化** | ❌ 不支持 | ✅ 支持 |
| **进程重启** | 数据全部丢失 | **数据自动恢复** |
| **读性能** | 基准 | **2.4 倍提升** |
| **临时文件** | ❌ 不支持 | ✅ 自动清理 |
### 适用场景
**完美替代 HashMap 的场景**:
- 🚀 **大规模缓存** - 需要缓存 10GB+ 数据,但不想承受 GC 压力
- 💾 **持久化存储** - 需要简单的持久化 KV 存储,不想引入 Redis/RocksDB
- 🔄 **临时数据处理** - 海量临时数据需要暂存,自动清理避免泄露
- ⚡ **低延迟应用** - 对 GC 停顿零容忍的实时系统
- 📊 **数据分析** - 处理大数据集,内存放不下但需要高速访问
- 🎮 **游戏服务器** - 需要持久化玩家数据,但要求快速读写
## ✨ 特性
- ✅ **多种存储模式** - 支持 堆外内存、内存映射文件、内存映射临时文件 三种模式
- ✅ **持久化支持** - Mmap 模式支持数据持久化到磁盘,支持自动恢复
- ✅ **临时文件模式** - 支持自动清理的临时文件存储
- ✅ **零拷贝序列化** - 原始类型直接内存布局,无序列化开销
- ✅ **高并发支持** - 分段锁设计(64 个段),StampedLock 乐观锁优化
- ✅ **智能内存分配** - Slab Allocator 减少内存碎片
- ✅ **多种索引结构** - 支持 HashIndex、SegmentedHashIndex、LongPrimitiveIndex、IntPrimitiveIndex
- ✅ **类型安全** - 泛型支持,编译时类型检查
- ✅ **零依赖** - 核心库无第三方依赖
## 🚀 快速开始
### Maven 依赖
```xml
com.yomahub
roguemap
1.0.0-BETA1
```
### 基本使用
#### OffHeap 模式(堆外内存)
```java
import com.yomahub.roguemap.RogueMap;
import com.yomahub.roguemap.serialization.PrimitiveCodecs;
import com.yomahub.roguemap.serialization.StringCodec;
// 创建一个 String -> Long 的堆外内存 Map
try (RogueMap map = RogueMap.offHeap()
.keyCodec(StringCodec.INSTANCE)
.valueCodec(PrimitiveCodecs.LONG)
.maxMemory(100 * 1024 * 1024) // 100MB
.build()) {
// 存储数据
map.put("user1", 1000L);
map.put("user2", 2000L);
// 读取数据
Long score = map.get("user1");
System.out.println("Score: " + score);
// 更新数据
map.put("user1", 1500L);
// 删除数据
map.remove("user2");
// 检查存在
boolean exists = map.containsKey("user1");
// 获取大小
int size = map.size();
}
```
#### Mmap 临时文件模式
```java
// 自动创建临时文件,JVM 关闭后自动删除
RogueMap tempMap = RogueMap.mmap()
.temporary()
.allocateSize(500 * 1024 * 1024L)
.keyCodec(PrimitiveCodecs.LONG)
.valueCodec(PrimitiveCodecs.LONG)
.build();
```
#### Mmap 模式(持久化存储)
```java
// 第一次:创建并写入数据
RogueMap map1 = RogueMap.mmap()
.persistent("data/scores.db")
.allocateSize(1024 * 1024 * 1024L) // 1GB
.keyCodec(StringCodec.INSTANCE)
.valueCodec(PrimitiveCodecs.LONG)
.build();
map1.put("alice", 100L);
map1.put("bob", 200L);
map1.flush(); // 刷新到磁盘
map1.close();
// 第二次:重新打开并恢复数据
RogueMap map2 = RogueMap.mmap()
.persistent("data/scores.db")
.keyCodec(StringCodec.INSTANCE)
.valueCodec(PrimitiveCodecs.LONG)
.build();
long score = map2.get("alice"); // 100L(从磁盘恢复)
map2.close();
```
### 支持的数据类型
RogueMap 提供了零拷贝的原始类型编解码器:
```java
// Long 类型(高性能)
RogueMap longMap = RogueMap.offHeap()
.keyCodec(PrimitiveCodecs.LONG)
.valueCodec(PrimitiveCodecs.LONG)
.build();
// Integer 类型
RogueMap intMap = RogueMap.offHeap()
.keyCodec(PrimitiveCodecs.INTEGER)
.valueCodec(PrimitiveCodecs.INTEGER)
.build();
// String 类型
RogueMap stringMap = RogueMap.offHeap()
.keyCodec(StringCodec.INSTANCE)
.valueCodec(StringCodec.INSTANCE)
.build();
// 混合类型
RogueMap mixedMap = RogueMap.offHeap()
.keyCodec(StringCodec.INSTANCE)
.valueCodec(PrimitiveCodecs.DOUBLE)
.build();
```
**支持的原始类型**:`Long`, `Integer`, `Double`, `Float`, `Short`, `Byte`, `Boolean`
如果是对象类型,RogueMap也提供了对象的编码解析器:
```java
// 对象类型
RogueMap longMap = RogueMap.offHeap()
.keyCodec(StringCodec.INSTANCE)
.valueCodec(KryoObjectCodec.create(YourObject.class))
.build();
```
### 索引选择
RogueMap 提供了多种索引策略,适用于不同场景:
```java
// 场景1: 高并发读写,推荐分段索引(默认)
RogueMap concurrentMap = RogueMap.offHeap()
.keyCodec(StringCodec.INSTANCE)
.valueCodec(StringCodec.INSTANCE)
.segmentedIndex(64) // 64个段,减少锁竞争
.build();
// 场景2: 内存敏感,Long键,推荐原始索引
RogueMap memoryOptimized = RogueMap.offHeap()
.keyCodec(PrimitiveCodecs.LONG)
.valueCodec(PrimitiveCodecs.LONG)
.primitiveIndex() // 节省81%内存
.build();
// 场景3: 简单场景,推荐基础索引
RogueMap simpleMap = RogueMap.offHeap()
.keyCodec(StringCodec.INSTANCE)
.valueCodec(PrimitiveCodecs.INTEGER)
.basicIndex()
.build();
```
### 配置选项
#### OffHeap 模式配置
```java
RogueMap map = RogueMap.offHeap()
// 必需配置
.keyCodec(keyCodec) // 键的编解码器
.valueCodec(valueCodec) // 值的编解码器
// 可选配置
.maxMemory(1024 * 1024 * 1024) // 最大内存 (默认 1GB)
// 以下三种配置一种即可,或者不配置
.basicIndex() // 使用基础索引
.segmentedIndex(64) // 使用分段索引 (默认)
.primitiveIndex() // 使用原始索引(仅Long/Integer键)
.build();
```
#### Mmap 临时文件模式配置
```java
RogueMap map = RogueMap.mmap()
// 必须配置
.temporary() // 临时文件模式
.keyCodec(keyCodec) // 键的编解码器
.valueCodec(valueCodec) // 值的编解码器
// 可选配置
.allocateSize(10L * 1024 * 1024 * 1024) // 预分配大小 (默认 10GB)
// 以下三种配置一种即可,或者不配置
.basicIndex() // 使用基础索引
.segmentedIndex(64) // 使用分段索引 (默认)
.primitiveIndex() // 使用原始索引(仅Long/Integer键)
.build();
```
#### Mmap 文件持久化模式配置
```java
RogueMap map = RogueMap.mmap()
// 必需配置
.persistent("data.db") // 持久化文件路径
.keyCodec(keyCodec) // 键的编解码器
.valueCodec(valueCodec) // 值的编解码器
// 可选配置
.allocateSize(10L * 1024 * 1024 * 1024) // 预分配大小 (默认 10GB)
// 以下三种配置一种即可,或者不配置
.basicIndex() // 使用基础索引
.segmentedIndex(64) // 使用分段索引 (默认)
.primitiveIndex() // 使用原始索引(仅Long/Integer键)
.build();
```
## 📊 性能测试
在 MacBook Pro (M3, 18GB) 上测试 100 万条 Long->Object 数据的结果:
### RogueMap vs HashMap 性能对比
| 模式 | 写入 | 读取 | 写吞吐(ops/s) | 读吞吐(ops/s) | 堆内存(MB) | 优势 |
|------|------|------|---------------|---------------|------------|------|
| **HashMap** | 611ms | 463ms | 1,636,661 | 2,159,827 | 304.04 | 基准 |
| **RogueMap OffHeap** | 658ms | 251ms | 1,519,756 | **3,984,063** | **40.46** | 堆内存 **-87%**,读性能 **+84%** |
| **RogueMap Mmap临时** | 629ms | 212ms | 1,589,825 | **4,716,981** | **40.13** | 堆内存 **-87%**,读性能 **+118%** |
| **RogueMap Mmap持久** | **547ms** | **195ms** | **1,828,153** | **5,128,205** | **40.01** | 堆内存 **-87%**,读性能 **+137%**,写性能 **+12%**,**支持持久化** |
### 核心发现
**相比 HashMap,RogueMap 能做到**:
1. **堆内存占用减少 87%** - 从 304MB 降到 40MB,大幅降低 GC 压力
2. **读性能提升 2.4 倍** - Mmap 持久化模式读取速度从 463ms 提升到 195ms
3. **写性能提升 12%** - Mmap 持久化模式写入速度从 611ms 提升到 547ms
4. **支持数据持久化** - 进程重启后数据自动恢复,HashMap 完全不具备此能力
5. **支持临时文件** - 自动清理的临时存储,适合大数据量临时处理
**推荐模式**:
- 🏆 **Mmap 持久化** - 综合性能最优,支持持久化,适合生产环境
- ⚡ **Mmap 临时文件** - 超高读性能,自动清理,适合临时数据处理
- 🔧 **OffHeap** - 纯内存,适合不需要持久化的高速缓存
### 与其他存储引擎对比
测试数据(100 万条 Long->Object):
| 实现方式 | 写入 | 读取 | 写吞吐(ops/s) | 读吞吐(ops/s) |
|----------|------|------|---------------|---------------|
| **RogueMap Mmap持久化** | **632ms** | **202ms** | **1,582,278** | **4,950,495** |
| MapDB 持久化 | 2,764ms | 3,207ms | 361,794 | 311,817 |
| **性能对比** | **4.4x** | **15.9x** | **4.4x** | **15.9x** |
RogueMap 在保持简单 API 的同时,提供了远超传统嵌入式存储引擎的性能表现。
### 运行性能测试
```bash
# 运行 RogueMap 多模式对比
mvn test -Dtest=MemoryUsageComparisonTest
# 运行 RogueMap vs MapDB 对比
mvn test -Dtest=RogueMapVsMapDBComparisonTest
# 运行所有性能测试
mvn test -Dtest=*ComparisonTest
```
## 🏗️ 架构设计
```
RogueMap API
↓
Index Layer (HashIndex/SegmentedHashIndex/PrimitiveIndex)
↓
Storage Engine (OffHeapStorage/MmapStorage)
↓
Memory Allocator (SlabAllocator/MmapAllocator)
↓
UnsafeOps (Java 8 Unsafe)
↓
Off-Heap Memory / Memory-Mapped Files
```
### 核心模块
- **RogueMap** - 主类,提供 OffHeapBuilder 和 MmapBuilder 两个构建器
- **index** - 索引层
- `HashIndex` - 基础哈希索引,基于 ConcurrentHashMap
- `SegmentedHashIndex` - 分段哈希索引,64 个段 + StampedLock 乐观锁
- `LongPrimitiveIndex` - Long 键原始数组索引,节省 81% 内存
- `IntPrimitiveIndex` - Integer 键原始数组索引
- **storage** - 存储引擎
- `OffHeapStorage` - 堆外内存存储
- `MmapStorage` - 内存映射文件存储
- **memory** - 内存管理
- `SlabAllocator` - Slab 分配器,7 个大小类别(16B 到 16KB)
- `MmapAllocator` - 内存映射文件分配器,支持超过 2GB 的大文件
- `UnsafeOps` - 底层 Unsafe API 操作
- **serialization** - 序列化层
- `PrimitiveCodecs` - 原始类型零拷贝编解码器
- `StringCodec` - String 编解码器
- `KryoObjectCodec` - Kryo 对象序列化编解码器(可选)
### 内存管理机制
#### SlabAllocator(堆外内存)
- **分配策略**: 7 个 size class (16B, 64B, 256B, 1KB, 4KB, 16KB)
- **块大小**: 1MB
- **优化**: 空闲列表重用,负载因子自适应扩容
- **内存节省**: 相比 HashMap 节省 87% 堆内存
#### MmapAllocator(文件映射)
- **特点**: 使用 MappedByteBuffer 将文件映射到内存
- **大文件支持**: 单个分段最大 2GB,自动分多段处理
- **并发安全**: CAS 操作分配偏移量
- **双模式**: 支持持久化和临时文件
### 高并发支持
#### SegmentedHashIndex 并发机制
- **分段数量**: 64 个独立段
- **锁策略**: 每个段独立的 StampedLock
- **乐观读**: 读操作优先使用乐观读,验证失败时降级为读锁
- **性能**: 高并发场景下读性能提升 15 倍
#### LongPrimitiveIndex 并发机制
- **实现**: 原始数组 (long[] keys, long[] addresses, int[] sizes)
- **锁策略**: StampedLock 乐观读
- **内存优化**: 节省 81% 内存
## 📖 文档
- [性能测试报告](docs/PERFORMANCE_BENCHMARK.md)
## 🔧 构建项目
```bash
# 编译
mvn clean compile
# 运行测试
mvn test
# 运行特定测试
mvn test -Dtest=OffHeapFunctionalTest
mvn test -Dtest=MmapFunctionalTest
```
## 📝 系统要求
- Java 8
- Maven 3.6+
## ⚠️ 注意事项
1. **Unsafe API 警告** - 本项目使用 `sun.misc.Unsafe` API,这是内部 API,可能在未来版本中被移除。以后将添加 Java 17/21 的替代实现。
2. **内存管理** - 请确保正确关闭 RogueMap 实例以释放堆外内存:
```java
try (RogueMap map = ...) {
// 使用 map
} // 自动关闭,释放资源
```
3. **内存限制** - 堆外内存受 `-XX:MaxDirectMemorySize` JVM 参数限制,建议根据实际需求设置:
```bash
java -XX:MaxDirectMemorySize=2g -jar your-app.jar
```
4. **文件大小** - Mmap 模式的 `allocateSize()` 会立即占用磁盘空间,请根据实际需求设置
5. **并发安全** - RogueMap 是线程安全的,支持高并发读写
## 🤝 贡献
欢迎提交 Issue 和 Pull Request!
## 📄 许可证
本项目采用 [Apache License 2.0](LICENSE) 许可证。
## 🙏 致谢
本项目的设计灵感来自于:
- [MapDB](https://github.com/jankotek/mapdb) - 优秀的嵌入式数据库
- [Chronicle Map](https://github.com/OpenHFT/Chronicle-Map) - 高性能堆外 Map