SuperJ 快速开始
SuperJ 是什么
SuperJ 是一门采用 Java 语法的系统编程语言,通过 LLVM 提前编译为原生代码。你写的是看起来像普通 Java 的代码 — 类、接口、泛型、枚举、异常 — 得到的是一个自包含的原生二进制,没有 JVM,没有 JIT 预热,也没有垃圾回收器。
它不是 Java 的子集。它保留 Java 中让人愉悦、高效的部分,丢掉妨碍可预测原生性能的部分,并增加一层 Java 本不具备的系统级能力。结果就是读起来像 Java,跑起来像 C — 所以是 super Java。
为什么是“super”,而不是“subset”
子集只会做减法。SuperJ 既做减法又做加法:
保留 — Java 中好的部分 类与接口、单继承多接口、泛型(有界类型参数、通配符、菱形 <>)、枚举(每个常量可有主体)、带流作用域的 instanceof 模式匹配、方法引用(::)、可变参数、try/catch/finally、@Override、完整的运算符与控制流集合,以及熟悉的 String/集合体验。
移除 — 妨碍原生性能或确定性的部分 线程、锁、synchronized、volatile、java.util.concurrent(SuperJ 设计上就是单线程 — 用进程而非线程扩展);反射、ClassLoader 与 JPMS 模块(一切在编译期解决);lambda 与非静态内部类(没有隐藏的闭包机制 — 方法引用与静态嵌套类足以覆盖这些场景);自动装箱与受检异常;finalize()。
新增 — 普通 Java 缺失的现代系统级能力
- 用 arena 内存替代 GC — 确定性回收,没有 stop-the-world 停顿。可选的
arena/local关键字让你在需要时显式控制分配生命周期;其余由逃逸分析处理。 - 宽整数 —
i128、i256与i512作为一等公民原语。 struct— 固定布局、无头的线上格式记录(在字节缓冲上的轻量view(buf, off)视图),用于零拷贝协议代码。- 矩形数组 — 连续的
int[,]/int[,,]用于密集数值计算,与 Java 的锯齿int[][]并存。 - 一等公民 SIMD — 语言内建 Byte16/Float4/Double2/AVX2 内联函数。
- 构造上的 UTF-8 — 单一
string/String类型,按字节索引、以byte[]为后端存储、长度前缀(内嵌的 NUL 只是一个字节)。 native方法 — 当你需要直接操作底层时,通过修饰名(mangled)符号约定下沉到 C。- 开箱即用的系统 SDK — 一个非阻塞事件循环网络栈(
NioAdapter:TCP/UDP/Unix 套接字、epoll/kqueue、可选 io_uring)、增量式 HTTP/1.1 服务器、TLS 1.3、JSON、SEDA 事件驱动框架、日志,以及原始类型特化集合。
设计哲学
爱因斯坦有一句名言:任何聪明的傻瓜都能造出一个复杂的系统,但真正需要天才的是把系统做得尽可能简单 — 且不能再简单。SuperJ 的设计正是这一原则在一门语言上的具体实践。业界那些“显而易见的好东西” — 用线程做并发、用借用检查器做安全、源码级生态集成 — 每一个都是对真实问题的复杂解,而每一种情况下都存在一个更简单的解,它不是去管理问题,而是消除问题:
- 线程是并发的复杂解;进程 + 共享 mmap + 全序事件流(SEDA)是更简单的解。复杂解引入了不可判定的 bug(死锁自由性被证明是不可判定的);简单解消除了这一整类。参见 并发:一个论点。
- 借用检查器是内存安全的复杂解;单线程确定性是更简单的解。复杂解让每一行永远交税,只为让一类 bug 不可能发生;简单解几乎不付出任何代价,却让所有 bug 都可复现、可修复。参见 内存安全与安全。
- 源码级生态集成是“我们需要库”的复杂解;C-ABI 链接层是更简单的解。复杂解是单语言的,跨不过语言边界;简单解对每一门 LLVM 语言都有效,因为 SuperJ 也是其中之一。参见 生态。
在每种情况下,复杂解是你假设问题必须被管理时会伸手去拿的;简单解是当你发现问题可以被消除时就能得到的。复杂性不仅更难用 — 它还是不可判定的 bug、非确定性,以及单语言锁定所在之处。更简单不仅仅是更好;它更可能是正确的。下面四条原则就是这一理念的具体实例。
- 单线程确定性。移除并发不是限制 — 它正是要点。每个进程一个事件循环线程意味着没有锁、没有数据竞争、没有调度抖动,以及你可以推理的代码。用进程(
SO_REUSEPORT)横向扩展,而不是共享内存的线程。 - 没有 GC,没有停顿。arena 分配以确定性方式回收内存。实测的回报是近乎平坦的延迟曲线:HTTP 服务器在负载下保持 p99 ≈ p50 — 那种带 GC 的 JVM 费尽力气追求的尾部表现。
- 原生性能是基线。 AOT 编译到 LLVM、零分配热路径,以及系统 SDK 让 SuperJ 与已发表的最快框架处于同一档次 — 明文 HTTP 服务器的吞吐量在同等硬件上超过 TechEmpower 已发表的最快明文冠军,同时每个请求都执行完整的 HTTP 解析。
- 熟悉感降低了上述一切的成本。 Java 开发者立刻就能产出;新能力是可选的,不是前置条件。
安装
SuperJ 只需一条命令即可安装。唯一的宿主前置条件是一个 C 链接器(clang);其余一切都在包内。安装器会通过你所在平台的包管理器自动检测并自动安装缺失的依赖(OpenSSL、PCRE2、zstd、lz4)。
一行安装(把 <download-url> 替换为分发给你的 URL):
curl -fsSL <download-url>/install.sh | sh -s -- <download-url>
这一命令会下载安装器,检查并自动安装依赖,为你的 OS/arch 抓取 tarball + 校验和,验证它,解压到 ~/superj,并在你的 shell profile(bash/zsh/fish,自动检测)中设置 SJ_HOME 与 PATH。它还会运行一次链接验证测试(针对 -lcrypto 编译一个微型 C 程序),以确认工具链能产出可执行文件。幂等 — 重复运行是安全的。打开一个新 shell,然后:
superj --help
验证你的安装
安装之后,运行 superj doctor 确认构建所需的一切就绪:
superj doctor
它会检查 clang、OpenSSL、PCRE2、zstd 与 lz4 是否可用,运行一次链接测试(用与 superj build 相同的标志编译 + 链接一个 C 程序),并端到端地脚手架 + 构建一个微型测试项目。如果有任何缺失,它会打印针对你平台的确切安装命令。
SDK 变体
SuperJ 有三种发行风味,区别在于SDK 如何交付。传入 --sdk-variant(默认 community):
curl -fsSL <download-url>/install.sh | sh -s -- <download-url> --sdk-variant=community # 归档链接(默认,编译最快)
curl -fsSL <download-url>/install.sh | sh -s -- <download-url> --sdk-variant=enterprise # 全程序 -O3(运行时性能最佳)
curl -fsSL <download-url>/install.sh | sh -s -- <download-url> --sdk-variant=vip # 完整 SDK 源码(审计/修改)
三种变体:
| 变体 | 你得到什么 | 链接路径 | 权衡 |
|---|---|---|---|
| community(默认) | 预构建静态归档 + 桩 | 编译器链接归档;clang 链接最终二进制 | 链接最快;无跨模块全程序优化。安装体积最小。 |
| enterprise | 预编译 SDK 模块 + 目标文件 + 桩 | 编译器将 SDK 与你的程序链接并整体优化 | 跨 SDK + 用户代码的全程序优化(全局内联、死代码消除);链接较慢,运行时性能更好。 |
| vip | SDK 源码(.sj 文件,无预构建产物) | 编译器将 SDK 与你的源码一起编译(--sdk-source);clang 链接 | 最大优化 + 完整源码供审计/修改;构建最慢。 |
SDK 源码树(sdk/sj/)仅随 VIP 安装发布。community 与 enterprise 不发布 SDK 源码 — 它们发布预构建产物(community 是归档,enterprise 是编译好的 sdk.ll)以及 sdk/stubs/(类型检查器使用的仅含签名的声明)。因此 --sdk-source 只能在 VIP 安装上使用;在 community/enterprise 上请使用 --sdk-path(归档链接)或 --sdk-path … --enterprise(经由 sdk.ll 的全程序 LTO)。
你的代码在三者之间完全相同 — superj compile 会从 $SJ_HOME/sdk 自动检测已安装的模式,所以你通常不需要操心:
superj compile app.sj # 自动检测已安装模式,输出 IR
superj compile app.sj --link # … 并链接一个可执行文件(始终 -O3)
superj compile app.sj --link --enterprise # 强制全程序 LTO(需要 enterprise SDK)
superj compile --link 始终向 clang 传入 -O3(除非指定 --debug)。显式的 --sdk-path <dir>(community + enterprise)、--sdk-source <dir>(仅 VIP)与 --enterprise 会覆盖自动检测。一个不导入 sj.* 中任何内容的程序是完全独立的 — 根本不会链接 SDK。
优化标志
| 标志 | 效果 |
|---|---|
| (默认) | -O3 — 始终如此,除非指定 --debug |
--enterprise | 全程序 LTO:将 SDK 与你的程序链接并整体优化 |
--no-bounds-check | 禁用数组越界检查(热数值循环;约 1.1-1.5 倍加速) |
--simd <level> | sse2(默认,x86)、avx2(x86 256 位)、none(禁用)。ARM NEON 始终开启(此标志为空操作)。 |
--target-cpu <cpu> | clang -mcpu=<cpu>(例如 native、apple-m2) |
--debug | -O0 -g(1:1 调试行映射;无优化) |
最大性能:
superj compile app.sj --sdk-path "$SJ_HOME/sdk" --enterprise --link \
--no-bounds-check --simd avx2 --target-cpu native --output app
# 或通过构建系统:
superj build --release --enterprise
在 VIP 安装上(SDK 源码可用),改用 --sdk-source 而非 --sdk-path:
superj compile app.sj --sdk-source "$SJ_HOME/sdk/sj" --enterprise --link \
--no-bounds-check --simd avx2 --target-cpu native --output app
我用的是哪个变体?
检查 $SJ_HOME/sdk/build/ 里的内容:
ls $SJ_HOME/sdk/build/
- 一个归档 → community
- 一个预编译模块 + 目标文件 → enterprise
- 目录不存在(只有
sdk/sj/下的源码)→ vip
切换变体意味着重新运行另一个安装器。
Hello, SuperJ
SuperJ 在 superj 二进制中内置了一套完整的构建系统。一条命令搭建项目;再两条命令构建并运行:
superj new myapp # 脚手架:Build.sj + src/myapp/Main.sj + .gitignore
cd myapp
superj run # 编译 + 链接 + 运行,一步到位
你应该看到:
Hello from myapp
脚手架生成的项目:
myapp/
Build.sj ← 清单(名称、版本、入口、依赖)
.gitignore ← 忽略 target/
src/myapp/Main.sj ← package myapp; class Main { public static void main(String[] args) { ... } }
编辑 src/myapp/Main.sj:
package myapp;
public class Main {
public static void main(String[] args) {
System.out.println("hello from superj");
}
}
然后:
superj run # 重新构建 + 运行
superj build --release # 优化构建 -> target/release/myapp
superj check # 全项目类型检查(无编译/链接)
完整的构建系统功能 — Build.sj 清单字段、路径与 git 依赖、工作区、profile、构建钩子、feature flag、superj add、superj clean、superj test — 参见 构建系统。
使用 SDK
SuperJ SDK 随包发布在 $SJ_HOME/sdk/。一个导入了 sj.* 类(集合、HTTP、JSON、SEDA、加密、…)的程序会自动针对已安装的 SDK 编译 — 无需任何标志:
superj run # 自动检测已安装的 SDK 模式
要查看完整的 SDK API 全貌 — 每个类、方法与签名集中在一个文件 — 运行 superj sdk-api(它打印到 stdout;如果想保留,重定向到文件)。查看单个类:
superj doc sj.http.Router # 打印 Router 的方法 + 签名
superj doc sj.util.IntArrayList # 打印 IntArrayList 的接口面
superj doc --list # 打印每个 SDK 类(FQN + 标签)
一组精选的示例程序覆盖了语言表面与所有 SDK 能力,随包发布在 $SJ_HOME/demo/ 下 — 按能力(http、json、seda、collections、…)浏览它,读一个示例,你就掌握了模式。
IntelliJ 插件(可选)
SuperJ 附带一个可选的 IntelliJ IDEA 插件(语法高亮、跳转到声明、查找用法、结构视图、运行配置)。该插件并非使用编译器所必需 — 它只是一个 IDE 便利工具。
安装一次,之后每次更新都自动获取,通过一个自定义插件仓库:在 IntelliJ 中,前往 Settings -> Plugins -> 齿轮图标 -> Manage Plugin Repositories -> +,并添加 SuperJ 插件仓库的 URL(随每次 release 的说明分发)。然后在 Marketplace 下搜索 SuperJ(它现在也会列出这个仓库)并安装;如果你已经装有旧版本,也可以使用 Check for updates。无需 IntelliJ SDK、JDK,也无需手动拷贝 jar — 这与普通插件更新走的是同一条路径。
如果你更愿意自己从源码构建插件,请参阅源码仓库中的贡献者文档,获取手动构建与安装步骤。
接下来去哪
- 构建系统 —
superj new/build/run/check/test、Build.sj清单、依赖、工作区、profile、钩子。 - 编写与运行测试 —
sj.test框架与 golden-output 测试套件。 - 内存安全 — arena 模型,以及 SuperJ 如何在没有垃圾回收器的情况下保持内存安全。
- 并发 — 设计上的单线程模型;用进程而非线程扩展。
- 生态 — 开箱即用的系统 SDK(HTTP 服务器、SEDA 事件框架、加密、集合)。
superj doc --list— 浏览 SDK API 全貌(每个类与签名);superj doc <class-fqn>打印单个类的方法。