news 2026/11/5 18:22:16

仓颉编程语言 Runtime 环境变量使用手册:堆、GC、线程栈与 GWP-Asan 内存安全检测配置指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
仓颉编程语言 Runtime 环境变量使用手册:堆、GC、线程栈与 GWP-Asan 内存安全检测配置指南
  • 文档
  • 编程语言

【免费下载链接】cangjie_docs

仓颉编程语言开发者文档。

项目地址:https://gitcode.com/Cangjie/cangjie_docs
点击查看免费下载

仓颉(Cangjie)编程语言的 runtime(运行时)为仓颉可执行程序提供内存分配、垃圾回收(GC)、线程管理等底层能力。runtime 暴露了一系列环境变量,允许开发者在不改动代码的前提下,针对不同业务场景精细调优堆大小、GC 策略、region 分配、线程栈/并发数、运维日志输出等行为,并可通过 GWP-Asan 机制检测仓颉与 C 语言互操作中的堆内存安全问题。本文以官方文档 runtime_env.md 为骨架,结合仓库内编译选项、运行时部署、工具链手册等资料,完整梳理这些环境变量的语义、默认值、有效范围与实战用法,读完即可直接上手调优仓颉程序运行时。

环境变量的设置方式

仓颉运行时提供的环境变量均为进程级配置,需在启动仓颉程序之前设置到当前 shell 环境中。不同操作系统设置方式不同:

  • Linux shell 与 macOS shell:使用export命令。

    $ export VARIABLE=value
  • Windows cmd:使用set命令。

    > set VARIABLE=value

下文所有示例均基于 Linux shell 的export写法,若运行平台不符,请替换为对应平台的环境变量设置方式。环境变量仅在程序启动前设置才生效,程序运行期间修改不会影响当前进程;如需长期生效,可将配置写入.bashrc或系统环境变量。

运行时初始化可选配置

runtime 初始化参数用于控制堆、region 分配器与 GC 的默认行为。使用前需了解以下四条通用约束:

  1. 所有整型参数为Int64类型,浮点型参数为Float64类型;
  2. 所有参数如果未显式规定最大值,默认隐式最大值为该类型最大值;
  3. 所有参数若超出设置范围则设置无效,自动使用默认值;
  4. 所有参数在 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=1024kb

cjLargeThresholdSize:指定大对象阈值

需要大量连续内存空间的对象(例如长数组)称为大对象。堆内频繁分配大对象可能导致堆内连续空间不足,从而触发堆溢出问题。通过增大该阈值,可以让更多对象按大对象路径分配,从而提升堆内空间的连续性。

在仓颉语言中,大对象的阈值为cjLargeThresholdSize与cjRegionSize的较小者。cjLargeThresholdSize支持单位kb、mb、gb,有效范围为[4KB, 2048KB],默认值为32KB。

说明:

较大的大对象阈值可能影响程序性能,开发者应根据实际需求设置。

export cjLargeThresholdSize=1024kb

cjExemptionThreshold:指定存活 region 的水线值

取值(0, 1](Float64),该值与 region 大小相乘,若 region 中存活对象大小大于相乘后的值,则该 region 不会被回收(其中死亡对象继续占用内存)。该值指定得越大,region 被回收的概率越大,堆中碎片空间越少,但频繁回收 region 也会影响性能。默认值为0.8(80%)。

export cjExemptionThreshold=0.8

cjHeapUtilization:指定仓颉堆的利用率

取值(0, 1],是 GC 后更新堆水线(heap waterline)的参考依据之一。堆水线是指:当堆中对象总大小达到水线值时即触发 GC。该参数指定得越小,更新后的堆水线越高,触发 GC 的概率相对越低。默认值为0.8(80%)。

export cjHeapUtilization=0.8

cjHeapGrowth:指定仓颉堆的增长率

取值必须大于 0,同样是 GC 后更新堆水线的参考依据之一。增长率的计算方式为1 + cjHeapGrowth,参数值越大,更新后的堆水线越高,触发 GC 的概率越低。默认值为0.15,表示增长率为1.15。

export cjHeapGrowth=0.15

cjAllocationRate:指定对象分配速率

指定仓颉运行时分配对象的速率,取值必须大于 0,单位为MB/s,表示每秒可分配对象的数量。默认值为10240,即每秒可分配 10240MB 对象。

export cjAllocationRate=10240

cjAllocationWaitTime:指定对象分配等待时间

取值必须大于 0,支持单位为s、ms、us、ns,推荐使用纳秒(ns)。若本次分配对象距离上一次分配对象的时间间隔小于该值,则分配将等待。默认值为1000 ns。

export cjAllocationWaitTime=1000ns

cjGCThreshold:指定仓颉堆的参考水线值

支持单位为kb、mb、gb,取值必须为大于 0 的整数。当仓颉堆大小超过该值时,触发 GC。默认值为堆大小(即由cjHeapSize决定的值)。

export cjGCThreshold=20480KB

cjGarbageThreshold:指定 region 回收候选判定阈值

当 GC 发生时,如果 region 中死亡对象所占比率大于该环境变量,此 region 会被放入回收候选集中,后续可被回收(若受到其他策略影响也可能不被回收)。默认值为0.5,无量纲,有效区间为[0.0, 1.0]。

export cjGarbageThreshold=0.5

cjGCInterval:指定两次 GC 的间隔时间

取值必须大于 0,支持单位为s、ms、us、ns,推荐使用毫秒(ms)。若本次 GC 距离上次 GC 的间隔小于该值,则本次 GC 将被忽略。该参数用于控制 GC 的频率,默认值为150 ms。

export cjGCInterval=150ms

cjBackupGCInterval:指定备份 GC 的间隔

取值必须大于 0,支持单位为s、ms、us、ns,推荐使用秒(s)。当仓颉运行时在该参数设定时间内未触发 GC,则触发一次备份 GC(backup GC),防止堆长期无 GC 导致内存膨胀。默认值为240 秒(4 分钟)。

export cjBackupGCInterval=240s

cjProcessorNum:指定仓颉线程的最大并发数

有效范围为(0, CPU 核数 × 2],超出范围的设置无效,使用默认值。runtime 会调用系统 API 获取 CPU 核数,若获取成功,默认值为 CPU 核数;否则默认值为8。

export cjProcessorNum=2

cjStackSize:指定仓颉线程的栈大小

支持单位为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=100kb

MRT_LOG_PATH:指定运维日志输出路径

指定 runtime 运维日志的输出路径。若该环境变量未设置或路径设置失败,运维日志默认打印到stdout(标准输出)或 stderr(标准错误)。

export MRT_LOG_PATH=/home/cangjie/runtime/runtime_log.txt

MRT_LOG_LEVEL:指定运维日志最小输出级别

大于等于该级别的日志会被打印,默认值为e(ERROR)。支持值[v|d|i|w|e|f|s],含义分别为:

取值级别含义
vVERBOSE最详细,含所有运行信息
dDEBUG调试信息
iINFO常规信息
wWARNING警告
eERROR错误(默认)
fFATAL致命错误
sFATAL_WITHOUT_ABORT致命但不终止进程
export MRT_LOG_LEVEL=v

MRT_REPORT:指定 GC 日志输出路径

指定 runtime GC 日志的输出路径。若该环境变量未设置或路径设置失败,该日志默认不打印。可用于观察 GC 触发时机与堆状态,辅助调优前述 GC 相关参数。

export MRT_REPORT=/home/cangjie/runtime/gc_log.txt

MRT_LOG_CJTHREAD:指定 cjthread 日志输出路径

指定 cjthread(仓颉线程)日志的输出路径。若该环境变量未设置或路径设置失败,该日志默认不打印。

export MRT_LOG_CJTHREAD=/home/cangjie/runtime/cjthread_log.txt

cjHeapDumpOnOOM:是否输出堆快照

指定是否在发生堆溢出(OutOfMemoryError)后输出堆快照文件,默认不开启。支持值为[on|off],设定为on时开启,设定off或其他值不开启。

export cjHeapDumpOnOOM=on

cjHeapDumpLog:指定堆快照输出路径

指定堆快照文件的输出路径。注意:指定的路径必须已存在,且应用执行者对其具有读写权限。如果不指定,堆快照文件将输出到当前执行目录。

export cjHeapDumpLog=/home/cangjie

运行环境可选配置

以下参数用于控制运行时对栈溢出等异常场景的处理行为。

MRT_STACK_CHECK:开启 native stack overflow 检查

开启 native stack overflow 检查,默认不开启。支持设置为1、true、TRUE开启该功能。

export MRT_STACK_CHECK=true

CJ_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=true

cjGwpAsanSampleRate:设置采样频率

在 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
cjRegionSizeregion 分配器线程本地缓冲区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 + 值)无量纲> 00.15
cjAllocationRate对象分配速率MB/s> 010240
cjAllocationWaitTime对象分配等待时间s/ms/us/ns> 01000ns
cjGCThreshold触发 GC 的堆参考水线kb/mb/gb正整数堆大小
cjGarbageThresholdregion 回收候选判定阈值无量纲[0.0, 1.0]0.5
cjGCInterval两次 GC 最小间隔s/ms/us/ns> 0150ms
cjBackupGCInterval备份 GC 间隔s/ms/us/ns> 0240s
cjProcessorNum线程最大并发数无(0, CPU核数×2]CPU 核数(获取失败时 8)
cjStackSize线程栈大小kb/mb/gbLinux [64KB, 1GB] / Windows [128KB, 1GB]128KB
MRT_LOG_FILE_SIZE运维日志文件大小kb/mb/gb> 010MB
MRT_LOG_PATH运维日志输出路径路径—stdout/stderr
MRT_LOG_LEVEL运维日志最小级别v/d/i/w/e/f/s—e
MRT_REPORTGC 日志输出路径路径—不打印
MRT_LOG_CJTHREADcjthread 日志输出路径路径—不打印
cjHeapDumpOnOOMOOM 后输出堆快照on/off—off
cjHeapDumpLog堆快照输出路径路径路径需存在且可读写当前执行目录
MRT_STACK_CHECK开启 native 栈溢出检查1/true/TRUE—关闭
CJ_SOF_SIZEStackOverflowError 折叠栈长度intint 范围32(栈顶)
cjEnableGwpAsan开启 GWP-Asan 检测(仅 Linux/OpenHarmony)1/true/TRUE—关闭
cjGwpAsanSampleRateGWP-Asan 采样频率次(0, 2³¹-1]5000
cjGwpAsanHelp输出 GWP-Asan 帮助信息1/true/TRUE—关闭

调优时遵循"先观测、再调整"的原则:优先通过MRT_LOG_PATH、MRT_REPORT等日志观察堆与 GC 实际行为,再针对性地调整堆大小、GC 间隔与 region 相关参数;涉及 C 互操作的场景按需开启 GWP-Asan 并调整采样率,在性能开销与检测覆盖之间取得平衡。

  • 文档
  • 编程语言

【免费下载链接】cangjie_docs

仓颉编程语言开发者文档。

项目地址:https://gitcode.com/Cangjie/cangjie_docs
点击查看免费下载

相关推荐

上一篇:30亿参数撬动企业AI变革:IBM Granite-4.0-H-Micro重新定义轻量化智能部署
下一篇:Pulse v6.4.0-rc.7 告警引擎演进全解析:滚动窗口评估、容量预测与事件日志权威化

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 23:06:28

C语言大作业实战:学生信息管理系统的链表与文件读写拆解

简介&#xff1a;一份来自西北工业大学课程要求的C语言大作业工程包&#xff0c;包含两个独立题目&#xff1a;绘制杨辉三角与借书方案。绘制杨辉三角涵盖二维数组存储、嵌套循环输出、条件判断控制格式以及自定义函数计算二项式系数等核心语法&#xff1b;借书方案则模拟图书馆…

作者头像 李华
网站建设 2026/11/1 14:07:20

Boost 1.78 预编译动态库与 MinGW-w64 7.3.0 集成实战指南

简介&#xff1a;一套面向Windows 64位平台的Boost 1.78动态库编译包&#xff0c;采用MinGW 7.3.0工具链生成&#xff0c;同时打包Debug与Release两种版本&#xff0c;专门服务使用Qt Creator的C开发者。压缩包文件总量超过一万五千个&#xff0c;其中包含一万四千五百余个hpp头…

作者头像 李华
网站建设 2026/10/21 14:46:59

从机器人到数字人:用MATLAB打通数学主线与运动学实现

简介&#xff1a;这份资源是面向高年级本科生、研究生及工程师的机器人学教材&#xff0c;聚焦从传统机器人分析到数字人体建模的完整知识链路&#xff0c;并系统讲解MATLAB编程在其中的落地应用。作者Edward Y.L. Gu结合在克莱斯勒AM部门的实习经验与奥克兰大学机器人学、非线…

作者头像 李华
网站建设 2026/11/5 8:08:54

GPT-6加持ChatGPT:回复更可视化更具交互性

OpenAI Group PBC表示&#xff0c;ChatGPT正在摆脱传统的纯文字回复方式&#xff0c;为用户提供更具交互性的界面体验。在今日的媒体简报会上&#xff0c;该公司表示其GPT-6模型现在将能够使用一种“智能UI”功能&#xff0c;这将允许聊天机器人在其认为必要时生成更多视觉化输…

作者头像 李华
网站建设 2026/10/20 16:43:07

微信协议接口推荐:iPad 协议和 Mac 协议的稳定性差异实测

接入 WTAPI 写的第一个参数&#xff0c;就是 getLoginQrCode 里的 type——ipad 还是 mac。很多开发者随手一填就过去了&#xff0c;直到上线后半夜掉线&#xff0c;才发现这个参数决定了你的机器人能不能自己爬起来重连。这篇把两种协议在官WTAPI文档里能确认的差异讲清楚&…

作者头像 李华