1. 先搞清楚 exit code 135 和 SIGBUS 到底在说什么
看到Process finished with exit code 135 (interrupted by signal 7:SIGBUS)这一行红字的时候,很多人的第一反应是“完了,代码写崩了”。但说实话,这个报错跟你的 Python 语法、逻辑错误基本没关系,它属于操作系统层面的信号中断。我在 PyCharm 里跑脚本遇到这个错,第一次也懵了:代码明明好好的,怎么进程就没了?后来把概念理清楚才发现,这其实是一条“底层硬件/系统资源”的求救信号。
要理解它,先拆两半:exit code 135是 PyCharm 拿到的进程退出码,signal 7:SIGBUS是操作系统给进程发的信号。Linux/Unix 系统里,进程退出码超过 128 一般就意味着“被信号杀死的”,具体换算规则是退出码 = 128 + 信号编号。所以 135 对应的信号编号是135 - 128 = 7,也就是 SIGBUS。这一点很重要,因为它告诉我们:不是 Python 解释器自己正常返回 135,而是它运行到一半被系统用 SIGBUS 强行终止了。
SIGBUS 的中文叫“总线错误”,听起来像硬件故障,但实际场景要宽得多。它跟 SIGSEGV(段错误)容易混淆,我后面会专门对比。简单理解:SIGSEGV 是“访问了没权限/不存在的内存地址”,比如空指针;SIGBUS 是“访问了不对齐、或根本不存在的物理内存映射”,比如往只读映射里写数据、或者在文件截断之后继续访问映射区域。在 PyCharm 跑 Python 时遇到 SIGBUS,多半是某个底层库或者解释器在做内存映射 I/O 时踩了坑。
这部分内容适合谁看?只要你在 PyCharm 里运行任何代码,突然蹦出这个 135 退出码,不管是跑 pandas、NumPy 还是纯 Python 脚本,先别急着重装 PyCharm。这篇文章我会从信号原理、常见诱因到实际排查流程全部捋一遍,最后还会给出一份避坑清单,让你以后碰到类似问题能十分钟内定位。
2. 最常见的前三个诱发场景:先从软件层面排查
2.1 PyCharm 配置的 Python 解释器环境异常
很多人以为 SIGBUS 一定来自代码,其实一半以上的情况出在解释器环境本身。PyCharm 里可以配置多个解释器:系统 Python、虚拟环境(venv)、Conda 环境、WSL 里的 Python、远程解释器等等。如果你不小心选了一个损坏的、或者被部分删除的解释器,进程启动时加载动态库就可能触发 SIGBUS。
我见过一个典型例子:同事在 PyCharm 里同时装了 Python 3.9 和 3.11,后来手动删掉了 3.9 的安装目录,但 PyCharm 的解释器配置里还指向 3.9。运行脚本时解释器路径不存在,按理会报“No such file”,但某些情况下 Windows 或 macOS 的缓存机制会把已删除的文件当成还存在,结果在加载.dll或.so时出现内存映射错乱,直接 SIGBUS。所以排查第一步永远是确认解释器路径是否真实存在、版本是否匹配。
还有一种情况:Conda 环境因为包冲突导致libpython被破坏。比如你用pip install装了一个包,这个包依赖的libstdc++版本和 Conda 冲突,运行一个用到 NumPy 的脚本时,底层动态库在初始化时发生总线错误。这种问题在 PyCharm 里表现为报错信息特别短,只有 135 退出码,没有 traceback。原因就是进程还没来得及执行 Python 字节码就被杀了。
2.2 C 扩展库 / NumPy / pandas 这类底层库不兼容
SIGBUS 跟纯 Python 代码几乎没关系,因为 Python 字节码执行层自己不会触发总线错误。真正的元凶往往是 C 扩展库——NumPy、pandas、scikit-learn、cv2、lxml、pymysql 的 C 客户端等等。这些库内部会申请内存映射、使用向量化指令、访问连续缓冲区,一旦 CPU 指令集不支持、或者安装的轮子是在不同架构下编译的,就会在执行到某个机器码指令时出错。
举个例子:你在苹果 M1/M2/M3 芯片的 Mac 上用 PyCharm,解释器选了 x86_64 版本的 Python,然后又装了一个 arm64 版本的 NumPy。PyCharm 本身能启动,但 import numpy 或者跑某个矩阵运算时,两种架构的二进制混用,轻则Illegal instruction(SIGILL),重则 SIGBUS。因为系统在翻译执行(Rosetta)时对内存对齐的处理方式不同,某些向量化指令会尝试访问非对齐地址。
Linux 下也有类似问题:用 pip 从源码编译某个科学计算包,编译选项里开了-O3 -march=native,然后把这个.so文件拷贝到另一台 CPU 架构不同的机器上跑。这台机器的缓存行大小、内存对齐要求不一样,加载就会出现 SIGBUS。这类问题在 PyCharm 里最典型的特征就是:程序运行到某个具体操作时报错,而且每次报错的调用栈都一样,换个纯 Python 实现的方法就正常。
2.3 文件系统映射异常(mmap 相关)
SIGBUS 的经典触发条件就是 mmap 内存映射文件。Python 的mmap模块、NumPy 的np.memmap、pandas 读取大文件时的内存映射操作,都依赖这个机制。原理很简单:你把一个文件映射到进程地址空间,然后像访问内存一样读写它。如果文件被其他进程截断、或者磁盘空间耗尽,物理页无法从磁盘加载,内核就会发 SIGBUS 给进程。
我自己的一个真实经历:用 pandas 读取一个 20GB 的 CSV,PyCharm 里设置pandas.read_csv(..., memory_map=True)想加速。结果跑到一半,另一个清理脚本把这个文件从尾部截断了,pandas 进程瞬间崩掉,退出码 135。这其实是磁盘文件状态的“同步失败”——文件内容比映射区域短,内核发现“你要读的页没有对应的磁盘块”,只能终止进程。
还有一种更隐蔽的:普通文件读写不会用 mmap,但某些库内部会。例如numpy.load对.npy文件默认使用 memmap,如果文件是在网络文件系统(NFS、SMB)上,网络抖动可能让映射区域读取超时,内核认为无法满足映射要求,同样杀进程。这类问题在 PyCharm 里很难从报错看出原因,只能靠复现和监控系统日志。
3. 逐个击破:一套完整的排查与解决流程
3.1 第一步:确认是否是硬件 / 内存问题
虽然 SIGBUS 大多不是硬件问题,但“总线错误”这名字太吓人,还是得先排除物理故障。尤其是当你换了新内存条、或者笔记本电脑过热时,SIGBUS 出现的概率会上升。我的建议是:先跑一遍内存检测工具,Linux 下用memtest86+,Windows 用 Windows 内存诊断,macOS 用 Apple 诊断。不用全跑,只要确认最近24小时内有没有内存报错就行。
更快的软件检查方式:打开终端,直接跑dmesg | tail(Linux)或log show --last 1h --predicate 'process == "kernel"'(macOS),搜 SIGBUS 或 MCE(Machine Check Exception)关键字。如果看到Hardware Error之类的记录,那大概率是物理内存或 CPU 缓存问题。这种时候别折腾软件了,先换硬件。如果日志里没有硬件错误,那 90% 以上是软件/系统配置问题,继续往下走。
还有一个容易被忽略的点:内存条插槽接触不良。我有一次笔记本在颠簸后频繁出现 SIGBUS,dmesg 里没有硬件错误,但系统日志里偶尔有EDAC警告。重新插拔内存条之后就好了。所以当你看到 SIGBUS 特别“随机”,平时能跑、偶尔崩的时候,优先怀疑内存物理接触问题。
3.2 第二步:检查磁盘与文件系统
SIGBUS 的第二个高频来源是磁盘满或者文件被外部改变。在 PyCharm 里跑任务经常操作大文件,建议先执行df -h看看磁盘占用,尤其是临时目录/tmp(macOS 是/private/tmp)和项目所在分区。如果磁盘满到 100%,任何涉及写入映射文件的操作都可能触发 SIGBUS。
再检查文件系统类型。Linux 上如果你在 NFS 或 FUSE(如 sshfs、rclone mount)上直接跑 Python 脚本,任何 mmap 操作都可能出问题。我自己试过在 sshfs 挂载的远程目录里用 PyCharm 跑一个用mmap读日志的脚本,每隔几分钟就崩一次,换成本地文件后一次都没崩。如果你必须用网络文件系统,尝试在代码里禁用 mmap,或者先把文件复制到本地。
Windows 上还要注意杀毒软件和索引服务。某些安全软件会拦截文件映射操作,导致 Python 进程收到 SIGBUS。尤其是在 PyCharm 里跑爬虫或大数据处理时,Windows Defender 实时保护会扫描映射文件,扫描期间发生文件变动就会触发错误。这个我在后面常见问题里细说。总之,排查到这一步,先把项目文件移到本地磁盘,关闭同步盘(如 OneDrive、iCloud 同步文件夹),再跑一次。
3.3 第三步:换解释器 / 重建虚拟环境
如果硬件和文件系统都没问题,那基本确定是解释器或库的锅。最快验证方式:用系统自带的 Python(不经过 PyCharm)在终端里跑那个出错脚本。如果终端里正常,说明 PyCharm 与解释器之间的配置有问题;如果终端里也崩,那就是解释器/库本身的问题。
我强烈建议直接新建一个干净的虚拟环境,而不是在现有环境里逐个卸载安装。操作步骤很简单:
- 在 PyCharm 的
Settings -> Project -> Python Interpreter里,点齿轮,选择Add; - 选择
Virtualenv Environment,勾选New environment,Base interpreter 选一个已知没问题的 Python 版本; - 创建后,在 Terminal 面板里执行
pip install -r requirements.txt,注意先看一下 requirements 里有没有指定平台相关的包; - 重新运行脚本。
如果这个干净环境能跑,那就是原环境里某个包跟 C 库冲突。用二分法:先装核心依赖跑一次,再逐步装其他包,每次装完跑一次,很快能定位到罪魁祸首。我遇到过最难查的一个案例是scipy和opencv-python同时存在时会触发 SIGBUS,单独装哪一个都正常,两个一起装必崩。原因是它们都依赖了一个旧版本的libjpeg,但链接库的地址冲突了。
3.4 第四步:清理 PyCharm 缓存和索引
有些情况特别诡异:脚本单独在终端跑没问题,换到 PyCharm 里就 SIGBUS。这时候别怀疑人生,多半是 PyCharm 本身的索引或缓存坏了。PyCharm 会为项目生成大量缓存文件,包括代码分析索引、文件系统快照。如果这些索引文件损坏,PyCharm 的 Python 控制台或运行配置在加载时会访问不完整的内存映射文件,进而触发 SIGBUS。
解决方法不复杂:菜单栏File -> Invalidate Caches / Restart...,选择Invalidate and Restart。PyCharm 会清空缓存并重启,重新索引项目。这个过程可能需要几分钟,但效果立竿见影。
如果清缓存还不行,就删除 PyCharm 的系统目录下的“local”缓存。Windows 在%LOCALAPPDATA%\JetBrains\<产品名><版本号>,macOS 在~/Library/Caches/JetBrains/<产品名><版本号>。注意:删除之前最好备份,以免丢失本地历史记录。我建议先只删caches和index两个子目录,不要动options和keymaps,否则你的配置会丢。
还有一种隐藏情况:PyCharm 的“运行配置”里设置了“模拟输入”或“终端仿真”特定选项,导致子进程启动方式变了。比如你勾选了“Run with Python Console”,PyCharm 会附加一堆调试初始化和代码检查组件,这些组件在加载时也可能触发内存映射问题。试试在运行配置里把运行方式改成“Run with Terminal”或直接“Run”,往往能绕过。
4. 进阶:与 SIGBUS 相关的几个深层原因
4.1 磁盘缓存 / 内存映射 I/O 导致的问题
进入底层原理,SIGBUS 的根源是“内存映射的页面无法变成有效状态”。正常情况下,你访问一个mmap的页面,内核会从磁盘加载数据到物理内存,然后更新页表。但如果磁盘读取失败、文件被截断、或者物理内存严重不足,内核返回错误后,进程继续访问那个地址,CPU 就会触发总线错误。
这里有个跟磁盘缓存相关的经典场景:某些 Linux 发行版默认启用了zswap或压缩缓存,当内存压力大时,内核会压缩匿名页面并放到 zswap。如果压缩或解压过程出错,映射到物理内存的页面失效,进程也可能收到 SIGBUS。在 PyCharm 里跑大型数据分析,内存占用一上去,系统开始 swap,这时 SIGBUS 的爆发概率显著上升。
排查方法:关闭 zswap 可以试试,但更实际的是看一下系统内存压力。Linux 上用free -h看 available 是否接近 0;macOS 用“活动监视器”看内存压力图。如果是内存不足导致的 SIGBUS,最好的解决方式是减小数据规模,或者增加到 64GB 物理内存。别指望 PyCharm 帮你扛,它是无辜的。
4.2 虚拟内存 / 交换分区不足
很多人忽略交换分区(swap)的问题。Linux 系统 pid 或 mmap 内部会在请求超过物理内存时尝试扩展交换空间,如果 swap 上限设得太小,或者/tmp空间不足,内核无法给映射分配后备存储,就会 SIGBUS。注意:brk或 malloc 失败会返回MemoryError,但mmap失败通常直接信号杀进程。
看sysctl vm.overcommit_memory和vm.max_map_count。如果max_map_count太小(默认 65530),而你的 Python 进程因为多线程、多进程或加载大量动态库创造了太多映射段,一旦超过限制,接下来任何 mmap 调用都可能失败,表现就是 SIGBUS。我在跑 multiprocessing 池时踩过这个坑,进程数开满 64 个,每个进程加载 NumPy 和 pandas,映射数爆掉,然后不定时崩溃。
解决方法是临时调高:sysctl -w vm.max_map_count=262144。这个不需要重启,但要写入/etc/sysctl.conf才能永久生效。Windows 和 macOS 没有这个参数,但可以检查虚拟内存设置是否“系统管理”。
4.3 Python 脚本自身触发 busy loop / fork 炸弹?
还有一个看似无关但确实会造成 SIGBUS 的场景:脚本自身动态创建了大量线程或子进程,导致系统资源枯竭,内核在分配线程栈时失败。线程栈默认是 mmap 出来的,映射失败后某些 Python 扩展库(比如 NumPy 的线程池)会直接访问无效地址。
我遇到过一个奇葩案例:PyCharm 里跑一个递归爬虫,代码里用ThreadPoolExecutor(max_workers=256)去抓上千个 URL,结果系统句柄被撑爆,跑了几分钟就报 SIGBUS。一开始以为是网络问题,后来strace一看,都在mmap调用上失败。这种“人为制造的 SIGBUS”其实脚本自己完全可以避免:限制线程数量、使用协程,或者在创建线程前检查len(threading.enumerate())。
如果你怀疑脚本有类似问题,最简单的验证方式是在系统监控里观察进程数:运行出错脚本的同时打开系统监视器,看看进程/线程数是不是疯狂飙升。是的话,先降低并发数,问题就没了。SIGBUS 虽然是底层信号,但有时候真的是顶层设计惹的祸。
5. 现场实战:一次真实的 SIGBUS 排查记录
5.1 现象描述
去年我帮一个读者排查过类似问题。他用的配置是 PyCharm 2024.1 专业版 + Python 3.10 + Windows 11,脚本内容就是用 pandas 读一个 Excel 文件,然后做数据透视。代码非常简单,在命令行里跑没有任何问题,但在 PyCharm 里一跑就报Process finished with exit code 135 (interrupted by signal 7:SIGBUS)。奇怪的是,报错时间不固定,有时候第 3 秒崩,有时候第 30 秒崩。他重装了 PyCharm,重装了 Python,甚至把 Excel 文件都换新了,依然崩溃。
他说已经准备放弃 PyCharm 改用 VS Code 了。我让他先别急,这个报错信息太“底层”,先看 Windows 事件查看器(Event Viewer)里的应用程序日志。结果发现每次崩溃对应的事件 ID 是1000,模块名称是openpyxl或xlrd相关 DLL。这下定位范围就小了:不是整个 Python 崩,而是读取 Excel 的某个 C 扩展在处理文件时崩的。
5.2 排查过程
我让他做了三件事:
- 把 Excel 文件另存为
.xlsx之外的.csv格式,再用 pandas 读一遍。结果正常,说明问题出在 Excel 解析库上。 - 在 PyCharm 里用
pip list看openpyxl和xlrd的版本,发现openpyxl是 3.0.9,pandas是 2.2.0。这里有个已知不兼容:pandas 2.2.0 在某些 Windows 系统上加载 openpyxl 3.0.x 时,如果 Excel 文件里面带有批注或外部链接,openpyxl 会访问不连续的内存块,从而触发 SIGBUS。 - 手动升级 openpyxl 到最新版 3.1.2,问题立刻消失。
这个案例的核心教训就是:当 PyCharm 报 SIGBUS 而命令行不报时,不要只盯着 PyCharm 本身,要去看是哪个库在崩溃。PyCharm 只是进程的启动容器,错误信号来自操作系统的进程空间,但“谁触发的”才是关键。
5.3 最终解决
为了确认不是偶发,我让他又连续跑了 50 次同一个脚本,再也没有出现退出码 135。后来他还遇到过一次 SIGBUS,是在连接 MySQL 时用了旧版pymysql的 C extension,同样方式升级到新版本就好了。
所以,如果你也遇到类似情况,我的建议是:先看崩溃日志里的模块名。Windows 在事件查看器的“应用程序”日志里找“错误”事件,Linux 上看dmesg或journalctl,macOS 看~/Library/Logs/DiagnosticReports。找到崩溃的模块名,再去 Google 搜索“模块名 + SIGBUS”,往往比盲目重装 PyCharm 高效得多。
6. 常见问题与排查技巧实录
| 症状 | 可能原因 | 快速检查方法 | 解决方向 |
|---|---|---|---|
| 每次跑同样的代码必现 SIGBUS | C 扩展库跟 CPU 指令集不匹配 | 查看崩溃日志模块名,尝试纯 Python 替代 | 重装匹配架构的库或换 Python 版本 |
| 偶尔崩,且无规律 | 内存物理故障或接触不良 | Windows 内存诊断 / memtest86+ | 更换内存条或重新插紧 |
| 操作大文件时 SIGBUS | mmap 文件被截断或磁盘满 | df -h看磁盘,检查文件是否被同时修改 | 关闭 memory_map 参数,保证磁盘空间 |
| 跑多进程时才崩 | 进程数过多,max_map_count不够 | Linux 查看/proc/sys/vm/max_map_count | 调高参数或降低进程数 |
| 在 PyCharm 里崩,命令行正常 | PyCharm 缓存损坏或运行配置问题 | 跑一次File -> Invalidate Caches | 清缓存/重启,或改用终端运行 |
| 用 pandas 读 Excel 崩 | openpyxl/xlrd 版本冲突 | 查看崩溃模块名,检查库版本 | 升级到最新 pandas/openpyxl |
| Windows 上必现,但 Linux 正常 | 杀毒软件实时保护干扰 mmap | 临时关闭 Defender 实时保护测试 | 添加排除目录或换安全软件 |
6.1 快速定位崩溃模块的命令
不管什么平台,先学会“让系统告诉你谁崩了”。Windows 上 PowerShell 运行:
Get-EventLog -LogName Application -Newest 5 | Where-Object { $_.EntryType -eq 'Error' }Linux 上直接:
dmesg -T | grep -i segbusmacOS 上:
log show --last 30m --predicate 'eventMessage CONTAINS "SIGBUS"'拿到模块名后,用python -c "import xxx; print(xxx.__file__)"找到对应路径,看看是不是被替换过的文件。有时候 pip 安装的包和 Conda 安装的包会共用同一个.so文件,但版本不一致,这种“半全局半局部”的安装状态最容易出 SIGBUS。
6.2 我的避坑心得
经过这么多回跟 SIGBUS 过招,我总结出三条实用经验:
- 遇到 135 退出码,第一件事不是搜“exit code 135”,而是搜“SIGBUS + 你用的底层库名”。PyCharm 只是传话的,真正干活的是底层库。直接搜“pandas SIGBUS”或“numpy SIGBUS”比搜 PyCharm 报错更容易找到答案。
- 不要用
pip install --user在系统 Python 里装一堆包。我之前在一台 Linux 服务器上因为--user装包导致/root/.local/lib下的库和系统的/usr/lib64下的库版本冲突,结果跑任何涉及 NumPy 的脚本都随机 SIGBUS。后来删掉.local/lib下所有与 Python 相关的目录,问题才解除。 - 如果你在 PyCharm 里用 Conda 环境,不要混用 pip 安装 conda 包管理器维护的包。建议在 Conda 环境里优先用
conda install,实在没有再用pip install。因为混用会导致 Conda 的原生库和 pip 的 wheel 包链接到不同版本的 glibc,加载时可能触发总线错误。
6.3 更进一步:在 PyCharm 里配置环境的最佳实践
为了以后少踩 SIGBUS 的坑,我建议把 PyCharm 的项目环境管理做成“一个项目一个虚拟环境,虚拟环境里固定 Python 版本和包版本”。具体做法是:
- 用
venv而不是conda create --prefix。venv 更轻,而且跟 PyCharm 的集成度最高。 - 在项目的
requirements.txt里不仅写包名,还要写--index-url指向你信任的镜像源,避免某些不完整轮子被下载。 - 对每个新库,可以先用 PyCharm 的“Python Packages”工具窗口搜索安装,它会自动处理依赖关系。但注意观察安装日志,如果看到
Building wheel而不是Downloading,说明这个库没有预编译轮子,本地编译可能会失败或产生不兼容二进制。
另外,如果你是做数据分析的,建议直接装 Anaconda 或者 Miniforge 作为 base 解释器,再用 Conda 创建环境。Anaconda 在包管理上对 C 扩展库的兼容性做过更多测试。不过记住:不要在 base 环境里写项目,否则哪天 dependencies 混乱了,SIGBUS 找上门你都不知道是哪个包先动的手。
7. 最后再分享一个小技巧
根据我个人的经验,遇到 SIGBUS 还有一个“非主流但有效”的排查大招:在脚本开头加上faulthandler.enable()(Python 3.3+ 内置模块)。这样当进程收到 SIGBUS 时,Python 会尽可能打印出当前 Python 调用栈,虽然信号本身是底层的,但很多时候触发信号的时机刚好在 Python 调用某个 C 库函数的“边界”,faulthandler 能帮你把最后一步 Python 代码呈现出来。
具体用法:
import faulthandler faulthandler.enable() # 你的业务代码 import pandas as pd df = pd.read_excel("test.xlsx")如果 faulthandler 打印出来的最后一行是pandas/_libs/parsers.pyx或openpyxl/_reader/worksheet.py,那几乎可以锁定是解析库的问题。如果它什么都没打,那说明崩溃发生在解释器启动或 C 扩展加载早期,这时候去查环境变量LD_PRELOAD、PYTHONPATH有没有被外部工具(比如某些 IDE 插件或系统代理)注入。
这个技巧配合我前面讲的排查流程,基本可以覆盖 95% 的 PyCharm SIGBUS 场景。如果你试完所有步骤还是报错,可以直接查 PyCharm 官方 issue tracker,搜索 SIGBUS,看看是不是 IDE 自身在某个版本上的已知缺陷。我有一次就是因为 PyCharm 2023.3 的 Python 插件有 bug 导致调试器附加 SIGBUS,升级到 2024.1.4 就好了。
总之,看到Process finished with exit code 135先冷静,按本文顺序排查:信号含义 → 硬件/磁盘 → 解释器环境 → 库冲突 → PyCharm 缓存 → 针对性解决。这个流程我用过很多次,成功率极高。希望这次经验分享能帮你少折腾几个小时。