- 文档
- 编程语言
【免费下载链接】cangjie_docs
仓颉编程语言开发者文档。
仓颉(Cangjie)编程语言的 runtime(运行时)为仓颉可执行程序提供内存分配、垃圾回收(GC)、线程管理等底层能力。runtime 暴露了一系列环境变量,允许开发者在不改动代码的前提下,针对不同业务场景精细调优堆大小、GC 策略、region 分配、线程栈/并发数、运维日志输出等行为,并可通过 GWP-Asan 机制检测仓颉与 C 语言互操作中的堆内存安全问题。本文以官方文档 runtime_env.md 为骨架,结合仓库内编译选项、运行时部署、工具链手册等资料,完整梳理这些环境变量的语义、默认值、有效范围与实战用法,读完即可直接上手调优仓颉程序运行时。
环境变量的设置方式
仓颉运行时提供的环境变量均为进程级配置,需在启动仓颉程序之前设置到当前 shell 环境中。不同操作系统设置方式不同:
Linux shell 与 macOS shell:使用
export命令。$ export VARIABLE=valueWindows cmd:使用
set命令。> set VARIABLE=value
下文所有示例均基于 Linux shell 的export写法,若运行平台不符,请替换为对应平台的环境变量设置方式。环境变量仅在程序启动前设置才生效,程序运行期间修改不会影响当前进程;如需长期生效,可将配置写入.bashrc或系统环境变量。
运行时初始化可选配置
runtime 初始化参数用于控制堆、region 分配器与 GC 的默认行为。使用前需了解以下四条通用约束:
- 所有整型参数为
Int64类型,浮点型参数为Float64类型; - 所有参数如果未显式规定最大值,默认隐式最大值为该类型最大值;
- 所有参数若超出设置范围则设置无效,自动使用默认值;
- 所有参数在 OpenHarmony 平台下均无效,OpenHarmony 平台下仓颉运行时一律使用默认值。
cjHeapSize:指定仓颉堆的最大值
仓颉堆(heap)是 runtime 管理对象内存的区域。cjHeapSize指定堆的最大值,支持单位为kb(KB)、mb(MB)、gb(GB),有效范围为[4MB, 系统物理内存],超出范围的设置无效,仍使用默认值。
默认值规则:若物理内存低于 1GB,默认值为64MB;否则为256MB。OpenHarmony 与 Android 平台支持的最小配置值为 64MB,配置值低于该值时会自动回退到默认值。
export cjHeapSize=4GB实战参考:当程序因堆空间不足抛出VirtualMachineError OutOfMemoryError时,可通过增大该参数缓解。cjcov_manual.md 中针对覆盖率工具执行时的 OOM 场景给出了同样的建议:默认情况下仓颉分配 1MB 栈与 256MB 堆内存,通常 2GB 堆即可满足多数场景,不足时可继续按需调大:
export cjHeapSize=2GB此外,在宏替换(macro substitution)场景中,runtime 初始化配置默认使用宏提供的默认值,其中cjHeapSize与cjStackSize是用户可修改的两个参数(见 compiling_error_reporting_and_debugging.md)。
cjRegionSize:指定 region 分配器线程本地缓冲区大小
region 分配器将堆划分为若干 region 进行管理,每个线程拥有独立的本地缓冲区(thread local buffer)。cjRegionSize指定该缓冲区大小,支持单位为kb、mb、gb,有效范围为[4kb, 2048kb],默认值为64KB。macOS 平台支持的最小配置值为 16KB,低于该值的配置将使用默认值。
export cjRegionSize=1024kbcjLargeThresholdSize:指定大对象阈值
需要大量连续内存空间的对象(例如长数组)称为大对象。堆内频繁分配大对象可能导致堆内连续空间不足,从而触发堆溢出问题。通过增大该阈值,可以让更多对象按大对象路径分配,从而提升堆内空间的连续性。
在仓颉语言中,大对象的阈值为cjLargeThresholdSize与cjRegionSize的较小者。cjLargeThresholdSize支持单位kb、mb、gb,有效范围为[4KB, 2048KB],默认值为32KB。
说明:
较大的大对象阈值可能影响程序性能,开发者应根据实际需求设置。
export cjLargeThresholdSize=1024kbcjExemptionThreshold:指定存活 region 的水线值
取值(0, 1](Float64),该值与 region 大小相乘,若 region 中存活对象大小大于相乘后的值,则该 region 不会被回收(其中死亡对象继续占用内存)。该值指定得越大,region 被回收的概率越大,堆中碎片空间越少,但频繁回收 region 也会影响性能。默认值为0.8(80%)。
export cjExemptionThreshold=0.8cjHeapUtilization:指定仓颉堆的利用率
取值(0, 1],是 GC 后更新堆水线(heap waterline)的参考依据之一。堆水线是指:当堆中对象总大小达到水线值时即触发 GC。该参数指定得越小,更新后的堆水线越高,触发 GC 的概率相对越低。默认值为0.8(80%)。
export cjHeapUtilization=0.8cjHeapGrowth:指定仓颉堆的增长率
取值必须大于 0,同样是 GC 后更新堆水线的参考依据之一。增长率的计算方式为1 + cjHeapGrowth,参数值越大,更新后的堆水线越高,触发 GC 的概率越低。默认值为0.15,表示增长率为1.15。
export cjHeapGrowth=0.15cjAllocationRate:指定对象分配速率
指定仓颉运行时分配对象的速率,取值必须大于 0,单位为MB/s,表示每秒可分配对象的数量。默认值为10240,即每秒可分配 10240MB 对象。
export cjAllocationRate=10240cjAllocationWaitTime:指定对象分配等待时间
取值必须大于 0,支持单位为s、ms、us、ns,推荐使用纳秒(ns)。若本次分配对象距离上一次分配对象的时间间隔小于该值,则分配将等待。默认值为1000 ns。
export cjAllocationWaitTime=1000nscjGCThreshold:指定仓颉堆的参考水线值
支持单位为kb、mb、gb,取值必须为大于 0 的整数。当仓颉堆大小超过该值时,触发 GC。默认值为堆大小(即由cjHeapSize决定的值)。
export cjGCThreshold=20480KBcjGarbageThreshold:指定 region 回收候选判定阈值
当 GC 发生时,如果 region 中死亡对象所占比率大于该环境变量,此 region 会被放入回收候选集中,后续可被回收(若受到其他策略影响也可能不被回收)。默认值为0.5,无量纲,有效区间为[0.0, 1.0]。
export cjGarbageThreshold=0.5cjGCInterval:指定两次 GC 的间隔时间
取值必须大于 0,支持单位为s、ms、us、ns,推荐使用毫秒(ms)。若本次 GC 距离上次 GC 的间隔小于该值,则本次 GC 将被忽略。该参数用于控制 GC 的频率,默认值为150 ms。
export cjGCInterval=150mscjBackupGCInterval:指定备份 GC 的间隔
取值必须大于 0,支持单位为s、ms、us、ns,推荐使用秒(s)。当仓颉运行时在该参数设定时间内未触发 GC,则触发一次备份 GC(backup GC),防止堆长期无 GC 导致内存膨胀。默认值为240 秒(4 分钟)。
export cjBackupGCInterval=240scjProcessorNum:指定仓颉线程的最大并发数
有效范围为(0, CPU 核数 × 2],超出范围的设置无效,使用默认值。runtime 会调用系统 API 获取 CPU 核数,若获取成功,默认值为 CPU 核数;否则默认值为8。
export cjProcessorNum=2cjStackSize:指定仓颉线程的栈大小
支持单位为kb、mb、gb,有效范围:Linux 平台为[64KB, 1GB],Windows 平台为[128KB, 1GB],超出范围设置无效,使用默认值。默认值为128KB。
export cjStackSize=100kb为什么需要调整栈大小:在仓颉与 C 语言互操作(FFI)场景中,虽然仓颉(CJNative 后端)提供了栈扩展能力,但 C 函数的栈使用对仓颉是不可见的,因此 FFI 调用 C 函数仍然存在栈溢出风险(可能导致运行时崩溃或未定义行为)。开发者应结合实际需求调整cjStackSize配置(见 cangjie-c.md)。
运维日志可选配置
runtime 支持将内部运行信息输出为运维日志,便于排查问题。以下环境变量用于控制日志的文件大小、输出路径与级别。
MRT_LOG_FILE_SIZE:指定运维日志文件大小
默认值为10MB,支持单位为kb、mb、gb,设置值需大于 0。日志大小超过该值时,会重新回到日志开头进行打印(循环覆盖式写文件)。最终生成的日志大小会略大于MRT_LOG_FILE_SIZE。
export MRT_LOG_FILE_SIZE=100kbMRT_LOG_PATH:指定运维日志输出路径
指定 runtime 运维日志的输出路径。若该环境变量未设置或路径设置失败,运维日志默认打印到stdout(标准输出)或 stderr(标准错误)。
export MRT_LOG_PATH=/home/cangjie/runtime/runtime_log.txtMRT_LOG_LEVEL:指定运维日志最小输出级别
大于等于该级别的日志会被打印,默认值为e(ERROR)。支持值[v|d|i|w|e|f|s],含义分别为:
| 取值 | 级别 | 含义 |
|---|---|---|
v | VERBOSE | 最详细,含所有运行信息 |
d | DEBUG | 调试信息 |
i | INFO | 常规信息 |
w | WARNING | 警告 |
e | ERROR | 错误(默认) |
f | FATAL | 致命错误 |
s | FATAL_WITHOUT_ABORT | 致命但不终止进程 |
export MRT_LOG_LEVEL=vMRT_REPORT:指定 GC 日志输出路径
指定 runtime GC 日志的输出路径。若该环境变量未设置或路径设置失败,该日志默认不打印。可用于观察 GC 触发时机与堆状态,辅助调优前述 GC 相关参数。
export MRT_REPORT=/home/cangjie/runtime/gc_log.txtMRT_LOG_CJTHREAD:指定 cjthread 日志输出路径
指定 cjthread(仓颉线程)日志的输出路径。若该环境变量未设置或路径设置失败,该日志默认不打印。
export MRT_LOG_CJTHREAD=/home/cangjie/runtime/cjthread_log.txtcjHeapDumpOnOOM:是否输出堆快照
指定是否在发生堆溢出(OutOfMemoryError)后输出堆快照文件,默认不开启。支持值为[on|off],设定为on时开启,设定off或其他值不开启。
export cjHeapDumpOnOOM=oncjHeapDumpLog:指定堆快照输出路径
指定堆快照文件的输出路径。注意:指定的路径必须已存在,且应用执行者对其具有读写权限。如果不指定,堆快照文件将输出到当前执行目录。
export cjHeapDumpLog=/home/cangjie运行环境可选配置
以下参数用于控制运行时对栈溢出等异常场景的处理行为。
MRT_STACK_CHECK:开启 native stack overflow 检查
开启 native stack overflow 检查,默认不开启。支持设置为1、true、TRUE开启该功能。
export MRT_STACK_CHECK=trueCJ_SOF_SIZE:控制 StackOverflowError 异常栈折叠长度
当 StackOverflowError 发生时,runtime 会自动折叠异常调用栈方便阅读,折叠后栈帧层数默认值为32。可通过该环境变量控制折叠栈长度,支持设置为 int 范围内的整数,其语义为:
CJ_SOF_SIZE = 0:打印所有调用栈;CJ_SOF_SIZE < 0:从栈底开始打印环境变量配置层数;CJ_SOF_SIZE > 0:从栈顶开始打印环境变量配置层数;CJ_SOF_SIZE未配置:默认打印栈顶开始 32 层调用栈。
export CJ_SOF_SIZE=30仓颉 GWP-Asan 内存安全检测
在仓颉与 C 代码互操作的过程中,可能出现仓颉堆内存安全问题。仓颉 GWP-Asan提供了一种内存安全检测功能,可以在仓颉程序运行过程中检测代码是否存在仓颉堆内存安全问题。
其原理是:对仓颉语言标准库提供的acquireArrayRawData与releaseArrayRawData接口(参见《仓颉编程语言库 API 文档》std.core包一节)进行采样,记录并对比采样对象前后内存的Canary 数据,从而检测仓颉与 C 语言互操作过程中是否出现了仓颉堆内存安全问题。
仓颉 GWP-Asan 是一种基于采样的检测工具,可以通过设置不同的采样频率来平衡性能影响和检测覆盖率。在默认或更低采样频率下,CPU 性能损失和额外的内存占用极低。
说明:
仓颉 GWP-Asan 内存安全检测仅支持Linux 与 OpenHarmony操作系统。
cjEnableGwpAsan:开启 GWP-Asan 检测
仓颉 GWP-Asan 内存安全检测功能默认关闭。通过将环境变量cjEnableGwpAsan设置为1、true或TRUE可以开启该功能。
export cjEnableGwpAsan=truecjGwpAsanSampleRate:设置采样频率
在 GWP-Asan 开启状态下,可通过该环境变量设置采样频率。支持设置为 32 位整型数值范围内的正整数,即(0, 2^31 - 1]。默认值为5000,即每 5000 次acquireArrayRawData接口调用进行一次采样。
export cjGwpAsanSampleRate=1000说明:
采样会影响性能:采样率越高,对性能影响越大,能检出更多的问题;采样率越低,性能影响越小,检出的问题更少。请根据实际需求设置采样率。
cjGwpAsanHelp:输出 GWP-Asan 帮助信息
通过该环境变量设置是否在控制台输出 GWP-Asan 帮助信息,默认不开启。设置为1、true或TRUE时,会在控制台输出帮助信息。
export cjGwpAsanHelp=true约束限制
- 仓颉 GWP-Asan 是一种基于采样的内存检查工具,内存越界问题可能无法完全检出;
- 仓颉 GWP-Asan 对仓颉堆内存的越界检测范围有限:无法检测内存读越界访问,仅能检测部分写越界访问:
- 向前写越界 8 字节以内;
- 向后写越界到尾部的填充区域(根据数组对象长度的不同,填充区域可能为 0-7 字节)。
异常检测类型与错误报告
堆内存写越界
堆内存写越界指的是指针实际访问的内存长度超过了数组申请的长度,造成仓颉堆内存写越界。
1. 向前越界
向前越界数组时,runtime 会报告Head canary检测失败,使用array[-1]表示。示例代码通过acquireArrayRawData获取数组原始数据指针后,向数组头部之前的越界位置写入:
unsafe { var array = Array<UInt8>(4, repeat: 1) var cp = acquireArrayRawData<UInt8>(array) cp.pointer.write(-1, 2) releaseArrayRawData(cp) }对应的错误报告如下:
2025-05-22 10:57:13.432786 41217 F Gwp-Asan sanity check failed on raw array addr 0x7f7c887368 2025-05-22 10:57:13.432863 41217 F Head canary (array[-1]) mismatch: expect: 0x4, actual: 0x200000000000004 2025-05-22 10:57:13.432878 41217 F Gwp-Asan Aborted.2. 向后越界
向后越界数组时,runtime 会报告Tail canary检测失败,并给出相对该数组(array)的位置。示例中数组实际可访问范围是[0, 4),而写操作访问了第 6 个字节,导致堆内存向后溢出 2 个字节,错误报告使用array[size+1]表示该行为:
unsafe { let array = Array<UInt8>(4, repeat: 0) let cp = acquireArrayRawData(array) // array 数组实际可访问的范围是 [0, 4),而下述写操作访问了第 6 个字节,导致仓颉堆内存向后溢出 2 个字节。错误报告中使用 array[size+1] 表示该向后越界行为。 cp.pointer.write(5, 2) releaseArrayRawData(cp) }对应的错误报告如下:
2025-05-22 10:53:09.564580 37872 F Gwp-Asan sanity check failed on raw array addr 0x7f6278a368 2025-05-22 10:53:09.564761 37872 F Tail canary (array[size+1]) mismatch: expect: 0x4, actual: 0x2 2025-05-22 10:53:09.564788 37872 F Gwp-Asan Aborted.仓颉 GC 异常
使用acquireArrayRawData获取了数组的指针,但未配套使用releaseArrayRawData释放数组的引用,可能造成仓颉 GC(Garbage Collection)异常。在 runtime 退出时会检测被采样的数组是否调用了releaseArrayRawData释放,未释放时会报告所有未释放数组对应的堆地址:
unsafe { let array = Array<UInt8>(4, repeat: 0) let cp = acquireArrayRawData(array) cp.pointer.read() // 未使用 releaseArrayRawData return }对应的错误报告如下:
2025-05-22 10:53:09.564761 1248614 F Unreleased array: 0x7fffd77f92d8 2025-05-22 10:53:09.564788 1248614 F Detect un-released array因此在使用acquireArrayRawData时必须保证成对调用releaseArrayRawData,避免泄漏数组引用导致 GC 异常。
补充:运行时配置的工程化实践
- 通过
cjpm配置测试环境变量:在cjpm的cjpm.toml配置中,[profile.test.env]段支持为测试进程注入运行时环境变量,例如cjHeapSize = { value = "32GB", splice-type = "replace" },可将运行时参数固化到工程配置中,与命令行export互补(见 cjpm_manual.md)。 - 与运行时部署配合:环境变量调优的前提是运行时动态库已正确部署。Linux 下需通过
LD_LIBRARY_PATH指向${CANGJIE_HOME}/runtime/lib/linux_${hw_arch}_cjnative,macOS 使用DYLD_LIBRARY_PATH(见 runtime_deploy.md)。若编译时使用--static全静态链接(仅 Linux 生效),runtime 模块已嵌入可执行文件,则无需额外部署运行时(见 compile_options.md)。 - 版本兼容注意:运行时加载仓颉包时会执行二进制兼容性检查(0.59.4 版本起),若运行时与包版本不兼容会终止执行或抛出
IncompatiblePackageException,调优前请确认运行时与库版本匹配(见 cangjie_package_compatibility.md)。
参数速查表
| 环境变量 | 作用 | 单位 | 有效范围 | 默认值 |
|---|---|---|---|---|
cjHeapSize | 仓颉堆最大值 | kb/mb/gb | [4MB, 物理内存] | 内存 <1GB 时 64MB,否则 256MB |
cjRegionSize | region 分配器线程本地缓冲区 | kb/mb/gb | [4kb, 2048kb] | 64KB |
cjLargeThresholdSize | 大对象阈值(取与 region size 的较小者) | kb/mb/gb | [4KB, 2048KB] | 32KB |
cjExemptionThreshold | 存活 region 水线 | 无量纲 | (0, 1] | 0.8 |
cjHeapUtilization | 堆利用率 | 无量纲 | (0, 1] | 0.8 |
cjHeapGrowth | 堆增长率(实际增长 = 1 + 值) | 无量纲 | > 0 | 0.15 |
cjAllocationRate | 对象分配速率 | MB/s | > 0 | 10240 |
cjAllocationWaitTime | 对象分配等待时间 | s/ms/us/ns | > 0 | 1000ns |
cjGCThreshold | 触发 GC 的堆参考水线 | kb/mb/gb | 正整数 | 堆大小 |
cjGarbageThreshold | region 回收候选判定阈值 | 无量纲 | [0.0, 1.0] | 0.5 |
cjGCInterval | 两次 GC 最小间隔 | s/ms/us/ns | > 0 | 150ms |
cjBackupGCInterval | 备份 GC 间隔 | s/ms/us/ns | > 0 | 240s |
cjProcessorNum | 线程最大并发数 | 无 | (0, CPU核数×2] | CPU 核数(获取失败时 8) |
cjStackSize | 线程栈大小 | kb/mb/gb | Linux [64KB, 1GB] / Windows [128KB, 1GB] | 128KB |
MRT_LOG_FILE_SIZE | 运维日志文件大小 | kb/mb/gb | > 0 | 10MB |
MRT_LOG_PATH | 运维日志输出路径 | 路径 | — | stdout/stderr |
MRT_LOG_LEVEL | 运维日志最小级别 | v/d/i/w/e/f/s | — | e |
MRT_REPORT | GC 日志输出路径 | 路径 | — | 不打印 |
MRT_LOG_CJTHREAD | cjthread 日志输出路径 | 路径 | — | 不打印 |
cjHeapDumpOnOOM | OOM 后输出堆快照 | on/off | — | off |
cjHeapDumpLog | 堆快照输出路径 | 路径 | 路径需存在且可读写 | 当前执行目录 |
MRT_STACK_CHECK | 开启 native 栈溢出检查 | 1/true/TRUE | — | 关闭 |
CJ_SOF_SIZE | StackOverflowError 折叠栈长度 | int | int 范围 | 32(栈顶) |
cjEnableGwpAsan | 开启 GWP-Asan 检测(仅 Linux/OpenHarmony) | 1/true/TRUE | — | 关闭 |
cjGwpAsanSampleRate | GWP-Asan 采样频率 | 次 | (0, 2³¹-1] | 5000 |
cjGwpAsanHelp | 输出 GWP-Asan 帮助信息 | 1/true/TRUE | — | 关闭 |
调优时遵循"先观测、再调整"的原则:优先通过MRT_LOG_PATH、MRT_REPORT等日志观察堆与 GC 实际行为,再针对性地调整堆大小、GC 间隔与 region 相关参数;涉及 C 互操作的场景按需开启 GWP-Asan 并调整采样率,在性能开销与检测覆盖之间取得平衡。
- 文档
- 编程语言
【免费下载链接】cangjie_docs
仓颉编程语言开发者文档。
相关推荐
仓颉编程语言完整开发环境配置终极指南
仓颉编程语言完整开发环境配置终极指南 仓颉编程语言是一款全场景智能化应用编程语言,为开发者提供了高效、安全的开发体验。本文将详细介绍如何快速搭建仓颉编程语言的完
文档知识库仓颉编程基础及应用:Windows 下仓颉 SDK(含编译器)下载、安装与环境变量配置实战
仓颉编程基础及应用:Windows 下仓颉 SDK(含编译器)下载、安装与环境变量配置实战 本文以随书仓库《仓颉编程基础及应用》 扩展阅读资料 https://
示例工程教程TCMalloc GWP-ASan 实战指南:用低开销采样检测生产环境的堆越界与 Use-After-Free
TCMalloc GWP ASan 实战指南:用低开销采样检测生产环境的堆越界与 Use After Free 导读 GWP ASan 是 Google TCM
内存管理系统编程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考