ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Unity报错排查:Copying assembly失败原因与解决方法

Unity报错排查:Copying assembly失败原因与解决方法 写这篇排障记录起因是群里有人发了一行 Unity 日志Copying assembly from Temp/Assembly-CSharp.dll to ...../Assembly-CSharp.dll后面跟着的是一长串路径看起来像是要拷贝程序集但结果却卡死或者报错。有人说这是 Unity 又抽风了也有人说直接删 Library 就能解决还有人劝重装编辑器。我当时正在处理一个类似的环境问题顺手就把这行日志的完整链路摸了一遍。今天把这次排查思路、操作顺序和最终结论整理出来希望能帮到被同样问题折腾的人。先说结论这行日志本身不是“错误”而是 Unity 脚本编译流程里一个非常正常的步骤。真正需要警惕的是它后面跟着的错误信息比如Access to the path is denied或者The process cannot access the file because it is being used by another process。大多数人只盯着Copying assembly这几个字就往“Unity 坏了”的方向想结果绕了很大一圈弯路。这篇文章的核心任务就是把这条日志背后的机制讲清楚并给出从浅到深的排查路径。1. 先把这个报错翻译成人话“Copying assembly”到底在干什么1.1 Assembly-CSharp.dll 不是普通 DLL而是所有脚本的“合并产物”很多 Unity 初学者看到Assembly-CSharp.dll这个名字会以为它是某个插件或者第三方库的一部分。其实它是你项目里所有 C# 脚本编译后生成的“主程序集文件”每当你修改一个 .cs 文件、调整脚本参数、切换平台Unity 都会重新编译生成新的Assembly-CSharp.dll。值得留意的是这个文件并不是直接生成在项目根目录的。Unity 默认的编译流程是编译器先把所有脚本代码编译到Temp/Assembly-CSharp.dll编译成功后Unity 再把这个 DLL 从Temp拷贝到Library/ScriptAssemblies/Assembly-CSharp.dll编辑器从Library/ScriptAssemblies里加载程序集Temp是编译工作区Library/ScriptAssemblies是加载缓存区。你把代码从“工作台”搬到“货架”上这个过程就是日志里写的Copying assembly from Temp/Assembly-CSharp.dll to ...../Assembly-CSharp.dll。1.2 “Temp/... → Library/ScriptAssemblies”这条链路的关键动作很多人第一次看到报错里的...../Assembly-CSharp.dll会一头雾水因为真实路径被日志截断了。如果你打开 Windows 的日志文件看完整信息会发现它实际上写的是Copying assembly from Temp/Assembly-CSharp.dll to C:/MyProject/Library/ScriptAssemblies/Assembly-CSharp.dll这里TEMP是放在项目文件夹下的一个临时目录不是系统盘的AppData/Local/Temp。Unity 把编译中间文件放在项目内的Temp里编译结束后再把成果考到Library/ScriptAssemblies。这一步通常在后台完成正常情况下一闪而过你根本看不到。只有当目标 DLL 被锁定、路径不可写、或者源文件损坏时这个“日常动作”才会变成一条刺眼的日志。1.3 拷贝失败不等于编译失败两类报错要分清这是排查时需要第一时间建立的概念。编译失败和拷贝失败在 Unity 控制台里的表现形式完全不同类型典型日志根本原因编译失败error CS0246: The type or namespace name xxx could not be found代码语法错误、程序集引用缺失拷贝失败Copying assembly from Temp/... to ....../Assembly-CSharp.dll failed文件被占用、路径权限异常、防病毒软件在干扰编译失败时Unity 会在控制台直接列出具体的代码错行和错误码方向很明确。而拷贝失败的日志往往只给一个结果错误码要么是IOException要么是UnauthorizedAccessException。一旦确认是后者就不要浪费时间去改代码了问题出在文件系统这一层。2. 动手前先排查环境路径、权限、同步盘和杀毒软件2.1 项目在不在 OneDrive / 坚果云 / 公司同步盘里这一步能筛掉一半问题我处理过的类似报错里有相当高比例的共同点是项目放在云同步目录里。OneDrive、坚果云、Dropbox、公司自建的同步盘都会对目录里的文件做实时扫描和状态标记。Unity 的编译是一个高频 I/O 操作一秒之内可能生成、删除、重写几十个临时文件。同步客户端一旦在某个瞬间抢占了目标 DLL 的句柄Unity 去复制文件时就会得到“文件被占用”的报错。如果你是团队协作可以问问其他同事有没有同样的报错。如果只有你自己有先看一眼项目路径在哪个父目录下。路径里带OneDrive、坚果云、Dropbox这类字样的基本就是第一嫌疑。2.2 杀毒软件实时防护它的“自动搞定”往往是罪魁祸首第二大类常见原因是杀毒软件的实时防护。Windows 自带的 Defender 也好第三方的 360、火绒、卡巴斯基也好都喜欢对可执行文件和 DLL 做“写时扫描”。Unity 刚从编译器拿到Temp/Assembly-CSharp.dll杀毒软件立刻凑上来读一遍、扫一遍、可能还隔离一下这个过程恰好和拷贝动作重叠于是拷贝失败。把项目目录加入杀毒排除列表是常见操作但很多人加错了位置。后面我会专门讲这个问题。2.3 TEMP 环境变量本身坏了才是真正的隐藏地雷有一种情况比较隐蔽不是项目目录下的Temp出问题而是Windows 系统级的临时目录%TEMP%出了毛病。Unity 在编译脚本程序集的过程中大量依赖TEMP环境变量对应的目录来存放中间文件。如果这个变量被指向了一个不存在、无权限或已被占用的路径编辑器日志里就会出现五花八门的 IO 异常。我在给那篇文章排查时也注意到相关热搜词里有大量类似“error writing temp”“unable to write inside temp environment variable”的内容。你可以先在 CMD 里快速自查一下echo %TEMP% echo %TMP%正常输出应该指向用户目录下 AppData 的 Local\Temp 文件夹像这样C:\Users\你的用户名\AppData\Local\Temp如果输出是一串乱码、为空、或者指向一个不存在的盘符那问题就从 Unity 环境变成 Windows 环境了。还有一种更隐蔽的情况TEMP 指向的目录存在但权限被限制当前用户的账户无法往里写文件。这通常会在登录用户都碰到类似“temp 临时账户”的时候一起出现。3. 从轻到重的解决顺序先做最小干预再决定要不要动用“重武器”3.1 第一步关闭 Unity 后清理项目内 Temp重建 Library/ScriptAssemblies 目录不要一上来就重建整个 Library那样会让 Unity 重新导入所有资源费时费力。更好的顺序是完全退出 Unity 编辑器打开项目根目录找到Temp文件夹删除里头的ScriptAssemblies子目录或者整个 Temp再进Library文件夹重命名ScriptAssemblies为ScriptAssemblies_Old重新打开项目这一步解决的是中间状态不一致的问题。假如上一次编译被强制中断Temp里的源 DLL 和Library/ScriptAssemblies里的目标 DLL 没对上Unity 的增量编译逻辑就可能钻进死胡同每次都在拷贝步骤上打转。清掉重来相当于让编译流程从零开始很多时候问题就消失了。需要注意项目正在被其他进程占用时Temp里的文件可能删不干净。如果删除时提示“文件正在使用”请先关掉 Unity Hub、代码编辑器、文件资源管理器里打开的对应目录再重试。3.2 第二步用系统工具定位锁定进程而不是靠猜如果清理后问题依旧那就不是缓存数据不一致的问题了而是某些进程正握着 DLL 不放手。Windows 下有现成工具可以用不必安装第三方软件打开资源监视器Win R 输入resmon切换到CPU标签页展开下方的关联的句柄在搜索框输入Assembly-CSharp.dll就能看到哪些进程持有了这个 DLL 的句柄如果你用的是 Sysinternals 套件也可以在管理员 CMD 里执行handle.exe -a Assembly-CSharp.dll输出会显示哪个 PID 占用了文件。看到进程列表后第一先看有没有Unity.exe、Unity Editor的多个残留实例这些是最常见的情况——上一次关编辑器没干净后台还挂着一个僵尸进程。杀掉残留进程后重新启动 Unity看日志是否恢复正常。3.3 第三步给杀毒软件加排除项注意是加路径不是加盘符如果锁文件的是杀毒软件或者系统提示“Access to the path is denied”就要检查实时防护的排除列表了。以 Windows Defender 为例操作路径是设置 → 隐私和安全性 → Windows 安全中心 → 病毒和威胁防护 → 管理设置 → 排除项。追加排除项时建议至少包含以下三条C:\Program Files\Unity\Hub\Editor\(版本号)\Editor D:\YourUnityProject你的项目根目录 %TEMP%注意很多人在这一环节会图省事直接把整个 C 盘或 D 盘加进排除列表。这样确实能解决问题但相当于把整块硬盘的安全防护都关了风险太大。更好的做法是只排除 Unity 安装目录、项目目录和临时目录路径越精确越好。给第三方杀毒软件设置时各家界面不一样但逻辑都一样找到“实时防护”或“文件系统防护”的排除设置把上述路径添加进去。设置完成后建议重启一次 Unity并且做一次全量重新编译来验证。3.4 第四步修复 TEMP / TMP 环境变量别让 Windows 的中间文件目录背锅如果排查到这里还没解决或者你观察到不只 Unity多个软件都报“无法写入临时目录”类错误就要马上检查系统环境变量。操作如下Win R 打开运行输入sysdm.cpl切到“高级”选项卡点击“环境变量”在“用户变量”和“系统变量”里找到TEMP和TMP确认它们指向的路径存在且当前用户有写入权限如果路径无效改成C:\Users\你的用户名\AppData\Local\Temp改完重启电脑TEMP 环境变量被污染通常是由某些安装程序或“系统优化”工具造成的。它们有时会把 TEMP 改到 D 盘某个目录再用清理工具把目录删了之后所有依赖临时文件的软件都会开始崩溃。Unity 的很多编辑器进程以及部分版本的编译后端都吃这个变量的状态。3.5 第五步最终验证不能只看编译器是否报错修复之后验证也有技巧。很多人看到 Unity 控制台不报红了就认为问题已经解决结果一进 Play 模式或者打包就重新爆出来。比较稳妥的验证方式是在项目里随便改一个脚本加一行注释或空行保存触发一次增量编译确认控制台没有Copying assembly相关错误进入 Play 模式跑几秒退出再执行一次 Windows 打包比如 Build 到本地文件夹关掉 Unity 重新打开项目四步全部走完才能放心交付给别人或继续开发。否则还可能残留着偶发性问题过几小时又出现。4. 一次完整踩坑记录从“偶发拷贝失败”到最后揪出真凶4.1 现象记录不是每次都失败只在全量重编译时出现我当时遇到的情况是项目原本好好的某天同事提交了一大批资源我在拉取后第一次打开项目Unity 进入了全量重编译状态。控制台滚动出一堆编译日志然后卡在Copying assembly from Temp/Assembly-CSharp.dll to ...../Assembly-CSharp.dll这里一直不动。等了五分钟没反应只能强制杀进程。重启编辑器后项目又恢复正常了。当时我以为只是偶发抽风没太在意。但第二天又出现了一次而且在同一个位置卡住我就意识到这不是偶发而是某个必然条件被触发了。4.2 第一次尝试删 Temp 文件夹问题暂时消失当时我做了大部分人会做的事退出 Unity删除项目根目录里的Temp然后重新打开。项目确实恢复正常了编译也顺利跑完。我当时心里还暗自高兴觉得自己找到了标准解法。但第三天同事又提交了一次大的资源改动问题原样出现。这说明最简单的“清理缓存”动作并没有触达问题根源只是掩盖了症状——编译前的内容被清掉后Unity 重新生成一套暂时绕开了占用冲突。4.3 关键转折在完整日志里看到真正出错的那一行第三次出现问题时我没有直接清理缓存而是先打开 Unity 的完整日志文件。Windows 下日志路径在C:\Users\你的用户名\AppData\Local\Unity\Editor\Editor.log往后翻在卡住的位置附近看到了关键线索Copying assembly from Temp/Assembly-CSharp.dll to ...../Assembly-CSharp.dll failed: Access to the path is denied.光这一行还不够我再往上翻了几百行又看到这些参与方的操作记录资源管理器正在扫描项目目录准备生成缩略图杀毒软件有多次 DLL 扫描记录同步盘客户端显示正在上传大量文件把三条信息凑在一起锁定的进程就已经不是 Unity 本身了。4.4 最终定位杀毒软件实时扫描 云同步盘双保险我用资源监视器的句柄搜索功能搜Assembly-CSharp.dll找到了两个非 Unity 进程一个是杀毒软件的实时防护模块另一个是云同步客户端的文件监听进程。它俩同时盯上了刚生成的 DLLUnity 还没完成拷贝资源已经被读了一遍又一遍。最终解决方式是组合拳把项目从同步盘目录迁出放到本地磁盘专用目录在杀毒软件里把项目目录和 Unity 编辑器的目录加进排除列表重启 Unity做一次全量编译之后这个问题就再也没出现过。整个过程让我意识到Unity 的这类报错本质上是文件系统竞争问题不是 Unity 自身的问题。排查思路必须从文件锁定的角度切入而不是急着重装编辑器。5. 防止问题复发我对 Unity 项目文件布局的一次彻底调整5.1 项目目录分层与 .gitignoreTemp/Library 绝不入版本库那次踩坑之后我把项目目录做了一次规范化调整。最核心的一条原则是Temp和Library永远不进入版本控制。如果你用 Git检查一下.gitignore里有没有这两条[Ll]ibrary/ [Tt]emp/ [Oo]bj/ [Bb]uild/有些团队为了方便喜欢把所有文件一股脑提交上去这会导致整个仓库越来越大还会在不同机器上产生各种缓存冲突。Library这个文件夹是从项目资源重算出来的是 UnityEngine 根据导入设置生成的本地缓存把它提交进版本库没有任何意义。Temp更是纯临时产物提交它只会让仓库变得混乱。正确的协作方式是让每台开发机器自己生成Library和Temp。第一次打开项目时可能较慢但后续增量编译是正常的。团队最好约定好这一点避免有人把本地缓存文件推送到远端。5.2 杀毒软件的排除配置给的是路径别只给盘符在团队内部沟通时要把杀毒软件排除项的配置方法也同步给所有人。我见过不少同事拿着网上的教程把整个盘符排除掉的这样虽然解决了 Unity 的问题但后续其他项目遇到病毒类风险时反而更难发现。更合理的做法是只在排除列表里添加这三类目录目录类型示例路径Unity 编辑器安装目录C:\Program Files\Unity\Hub\Editor\2021.3.30f1c1\Editor项目根目录D:\Work\MyGameProject系统临时目录%TEMP%注意最后一行要填%TEMP%不要展开成具体路径。因为不同用户登录环境的临时目录路径可能不同填变量可以让每台机器的杀毒软件都正确处理。5.3 单机开发者的自检流程遇到 File IO 相关报错先走这套动作如果你的项目是一个人开发没有团队协作也建议在每次大版本提交或者换电脑前做一套快速自检确认项目不在云同步目录里确认杀毒软件排除项是路径不是盘符确认 TEMP/TMP 环境变量指向有效路径关闭 Unity手动删除一次Temp和Library/ScriptAssemblies重新打开确认全量编译能一步跑通这套流程总共不到五分钟但能避免大部分文件 IO 类问题。我后来把这个流程写进了自己团队的开发文档里新人加入时先走一遍再遇到类似问题就能自己排查了。6. 由这个报错延伸出去的 Windows 临时目录健康问题6.1 为什么 AppData/Local/Temp 能堆出好几 GB 的文件Unity 项目里的Temp只是临时目录问题的一个缩影。系统级的AppData/Local/Temp更是重灾区这也是很多人在搜索“appdata/local/temp 为何这么多文件”的原因。简单解释一下Windows 把很多软件的运行期中间文件都写到这个目录下包括安装包解压过程中的临时文件、软件更新时下载的缓存、Office 文档的自动恢复文件、浏览器下载未完成的部分等。正常情况下大多文件应该在使用后被清理但有些软件崩溃、强制退出或没有实现清理逻辑就会把残渣留在 Temp 里。对 Unity 开发机来说AppData/Local/Temp里还会出现 Unity 自身的崩溃报告、Shader 编译中间结果等所以看到几百 MB 到几个 GB 的临时文件堆积一点都不奇怪。6.2 Windows 临时文件夹能不能直接删哪些能删哪些不能这是搜索相关词里被问得最多的一个问题“C 盘用户——图片里的 temp 文件夹能不能删”。我的建议是不要直接全选删除。原因有两方面第一正在被占用的文件无法删除系统会提示“文件正在使用”但一些批量删除工具会跳过或强行占用可能引发系统或软件崩溃。第二某些专业软件会在 Temp 里保存运行期配置。比如我见过一些遥感数据处理软件启动时要读取 Temp 路径下的config.txt如果系统刚被清理工具扫过配置文件被提前删了软件就会直接报couldnt open .../config.txt: no such file or directory。这类报错在相关搜索里也非常常见。所以正确的清理策略是关闭所有正在运行的软件尤其是 Unity、Office、浏览器和工程类软件重启电脑进入AppData/Local/Temp删除当前用户权限范围内能删的内容遇到“正在使用”提示直接跳过不要强行操作6.3 清理 Temp 的正确工具与时机平时使用 Windows 自带的“磁盘清理”或“存储感知”就够了cleanmgr可以扫描并清理系统临时文件、回收站、缩略图缓存存储感知在“设置 → 系统 → 存储”里可以定期自动清理临时文件对开发机来说我一般会在三种时间节点做临时目录清理Unity 项目长时间未打开后清理系统 Temp避免历史残留干扰新编译准备打包或做性能测试前清掉非必要的临时文件减少磁盘 I/O 干扰电脑磁盘空间告急时用磁盘清理工具做一次全盘扫描清理过程中如果看到 “error writing temp” 或 “unable to write inside temp environment variable” 这类提示先停下来检查 TEMP 环境变量是否有效。很多时候不是清理本身出了问题而是清理工具给 TEMP 指了一条不存在的路。写到最后再说一点体会Unity 开发中最容易把人带偏的就是“报错表面很吓人实际原因很朴素”的那类问题。Copying assembly from Temp/Assembly-CSharp.dll to ...../Assembly-CSharp.dll这行日志本身只是编译管线里的正常提示除非后面跟着failed之类的字眼否则根本不用管。如果真失败了优先怀疑文件被占用、路径权限、杀毒软件、云同步盘这四件事按顺序排查大概率能在十分钟内找到答案。
返回列表