• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Bundle包指针越界 Position out of bounds

武飞扬头像
绝不迟到陈瓜瓜
帮助1

开荒前言

掰一掰手指,今年已经是在游戏行业默默耕耘的第六年了。不经感叹时间过得好快,感觉自己每天忙忙碌碌却又好像没有留下过什么痕迹。回想起刚工作的时候就想要写个博客来记录成长的点点滴滴,却总因为各种琐事和偷懒的理由搁置了。一路走来有过挫折也有过很多次想要放弃的念头,但更多的还是解决一个又一个问题后的成就感。道阻且长,行则将至 行而不辍,未来可期。现在开始其实也不算晚,毕竟每一天都是未来的日子中最年轻的一天了。 从今天起写下一些文字,记录工作中遇到的各种问题,送给的每天进步的自己,也送给最好的你们。

关键词

  • Mismatched serialization in the builtin class ‘AssetBundle’.
  • The file ‘archive:/CAB-xxxxxx/CAB-xxxxxx’ is corrupted! Remove it and launch unity again!
  • [Position out of bounds!]

问题情境

在版本热更新以后有极少数玩家无法正常打开游戏,游戏运行到某些特定场景会触发闪退。清除缓存或者重新安装后可以解决问题,正常登陆游戏。

任务拆解

  • 找到触发条件
  • 快速解决生产环境的问题,缩小影响范围
  • 本地修复这个bug,在下个大版本更新时彻底解决这个问题

行动方法

碰到闪退的问题直接Bugly后台翻一翻崩溃日志,发现了一条崩溃记录且正好是走过热更的版本。
这样基本可以判断是更新后某些bundle包出现了问题导致了闪退发生

  • 错误记录
    学新通

  • 崩溃记录
    学新通

现在还不能说明发生错误的bundle包是热更后引起的,需要继续找到出问题的是哪个bundle包。
这里推荐一个视频 https://www.youtube.com/watch?v=mMjcDjM8Fm8 --Assetbundle细节解析 源自2018台北游戏开发者论坛 所以这么好的教学视频国内网站都没有呢0-0

编写脚本工具解析本地bundle包

  1. binary2text.exe工具 和 WebExtract.exe工具 在Unity安装目录中 比如 --> D:\Unity2020.3.17\Editor\Data\Tools 注意解析bundle包工具的unity版本要和制作时的一致
  2. 编写批处理文件批量解析本地bundle包 我是直接用C#写了 代码见后文 双击运行AnalyzeBundleInfo.exe即可
附上使用方法

学新通

附上C#代码
//用ide编译一下成exe即可
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace AnalyzeBundleInfo {
    internal static class Program {
        static string strCurrDirPath => System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
        static string strAssetBundleInfoDirPath => Path.Combine(strCurrDirPath, "AssetBundleInfo");
        static string strAssetbundleToolPath => Path.Combine(strCurrDirPath, "WebExtract.exe");
        static string strBundleTextToolPath => Path.Combine(strCurrDirPath, "binary2text.exe");
        static string strExtractBatchPath => Path.Combine(strCurrDirPath, "work.bat");
        static string strAnalyzeBatchPath => Path.Combine(strAssetBundleInfoDirPath, "work.bat");

        public static void Extract() {
            var arrFiles = Directory.GetFiles(strCurrDirPath);
            arrFiles = arrFiles.Where(s => !Path.HasExtension(s)).ToArray();
            var stringBuilder = new StringBuilder();
            for (int i = 0; i < arrFiles.Length; i  ) {
                var file = Path.GetFileNameWithoutExtension(arrFiles[i]);
                stringBuilder.AppendLine($"{strAssetbundleToolPath} {file}");
            }

            File.WriteAllText(strExtractBatchPath, stringBuilder.ToString());

            WorkCmd(strExtractBatchPath);
        }

        public static void CollectFile() {
            if (Directory.Exists(strAssetBundleInfoDirPath)) {
                Directory.Delete(strAssetBundleInfoDirPath, true);
            }

            var dirs = Directory.GetDirectories(strCurrDirPath);
            Directory.CreateDirectory(strAssetBundleInfoDirPath);

            for (int i = dirs.Length - 1; i >= 0; i--) {
                var newFiles = Directory.GetFiles(dirs[i]);
                var abName = Path.GetFileName(dirs[i]).Substring(0, Path.GetFileName(dirs[i]).Length - 5);
                newFiles = newFiles.Where(s => Path.GetFileName(s).ToUpper().StartsWith("CAB-")).ToArray();
                for (int j = 0; j < newFiles.Length; j  ) {
                    var strTargetFile = newFiles[j];
                    var strFileName = Path.GetFileNameWithoutExtension(strTargetFile);
                    var strExtName = Path.GetExtension(strTargetFile);
                    var strFinalName = $"{strFileName}_{abName}{strExtName}";
                    File.Copy(strTargetFile, Path.Combine(strAssetBundleInfoDirPath, strFinalName));
                }

                Directory.Delete(dirs[i], true);
            }
        }

        public static void AnalizeBundleInfo() {
            var newFiles = Directory.GetFiles(strAssetBundleInfoDirPath);
            newFiles = newFiles.Where(s => Path.GetFileName(s).ToUpper().StartsWith("CAB-") && !s.EndsWith(".resS")).ToArray();
            var stringBuilder = new StringBuilder();
            for (int i = 0; i < newFiles.Length; i  ) {
                var file = Path.GetFileName(newFiles[i]);
                stringBuilder.AppendLine($"{strBundleTextToolPath} {file} -detailed -hexfloat");
            }

            File.WriteAllText(strAnalyzeBatchPath, stringBuilder.ToString());
            WorkCmd(strAnalyzeBatchPath);
        }

        static void WorkCmd(string batFile) {
            var startinfo = new ProcessStartInfo(batFile);
            startinfo.UseShellExecute = true;
            startinfo.ErrorDialog = true;
            startinfo.CreateNoWindow = true;
            startinfo.WorkingDirectory = Path.GetDirectoryName(batFile);

            if (startinfo.UseShellExecute) {
                startinfo.RedirectStandardOutput = false;
                startinfo.RedirectStandardError = false;
                startinfo.RedirectStandardInput = false;
            }
            else {
                startinfo.RedirectStandardOutput = true;
                startinfo.RedirectStandardError = true;
                startinfo.RedirectStandardInput = true;
            }

            var p = Process.Start(startinfo);
            p.WaitForExit();
        }

        public static void Main(string[] args) {
            Extract();
            CollectFile();
            AnalizeBundleInfo();
        }
    }
}
学新通

比对检查结果

  • 找到了对应热更出错的bundle包
    学新通

  • 在运维svn中比对找到了热更包里的确有这个文件
    学新通

  • 猜测是热更包下载之后在安装环节产生了IO错误 类似在进行IO写入时本地bundle包并未卸载干净 导致bundle包头文件记录的内存地址与实际文件地址不相吻合从而引发了闪退

结果措施

  1. 后续版本不不热更部分资源(在热更新前被引用到的资源) 相应需要热更的部分尽量用lua代码去改
  2. 继续确认是IO发生了错误还是说老的bundle没有卸载 缓存的头文件地址成了野指针
  3. 优化一版热更流程

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgiffia
系列文章
更多 icon
同类精品
更多 icon
继续加载