• >
  • LIBMod
  • >
  • 并发修改什么的不要鸭 (CME is Bad)
并发修改什么的不要鸭 (CME is Bad)
模组属性评比

距离显示结果还剩2票~

路过的这位少侠,你觉得这款Mod怎么样,可否愿意来评一评它呢?登录并评比
更新日志
  • 暂无日志..

历史编辑记录更多
    管理组

      暂无管理组..

    编辑组

      暂无编辑组..

    活跃
    开源

    并发修改什么的不要鸭

    CME is Bad

    0.5

    闻所未闻

    昨日指数: 183
    昨日平均指数: 92.677

    6761

    总浏览

    --

    资料填充率


    如何下载?
    • 摘要

      在玩大型整合包的时候,常常会遇到并发修改异常(ConcurrentModificationException,CME)和下标越界异常(IndexOutOfBoundsException,IOOBE)等问题导致游戏崩溃。

      由于并发修改往往发生在多个不同的线程中,因而仅通过崩溃日志中一个线程的调用栈输出,通常无法确认是哪个模组导致的:

      并发修改什么的不要鸭 (CME is Bad)-第1张图片SimpleReloadInstance 的并发修改异常于是本模组应运而生,旨在通过输出一段时间内特定容器在每个线程被修改的历史,辅助玩家进行问题排查:

      并发修改什么的不要鸭 (CME is Bad)-第2张图片本模组可以输出一个容器的修改历史

      使用方法

      1. 将模组(jar 文件)放进 mods 文件夹,即和其它模组一样正常安装,无需在意加载器是什么。

      2. 在启动器(或保存有虚拟机参数的文件)中修改 Java 虚拟机参数(即 JVM 参数),向其中加入 “-javaagent:mods/CMESuckMyDuck-<version>.jar=<class full name>;<field name>;<type>;<phase>”(参数含义与示例见下文)。

      3. 启动游戏,运行并直到崩溃再次发生。

      4. 阅读游戏目录中的 CMESuckMyDuck.log 文件查看被监视容器的修改历史。

      参数含义

      class full name

      被监视容器所在类(class)的全名(即内部名,用“/”代替“.”,如“net/minecraft/server/packs/resources/SimpleReloadInstance”)。

      field name

      被监视容器的变量名,目前只支持类成员变量,不支持局部变量。

      对于 Forge,请使用 SRG 名(1.16.5 及以前如 field_123456_a,1.17 及以后如 f_123456_)。特别的,1.20.6 及以后的 Forge 请使用官方名。

      对于 Fabric,请使用 intermediary 名(包括类全名也要使用中间名,如 field_123456)。

      对于 NeoForge,请使用官方名(如 instances、structureRepository 等)。

      type

      被监视容器的类型,目前只支持 List、Set、Map。

      phase

      static 或 nonstatic,表示容器是类静态成员还是非静态成员。

      如何确认填什么参数

      这里我们举一个例子。首先我们根据 CME 或 IOOBE 的调用栈,确认容器所在的类:

      并发修改什么的不要鸭 (CME is Bad)-第3张图片SoundEngine 的并发修改异常的调用栈接着,阅读该类的代码,确认该类的哪个成员遭受了并发修改:

      并发修改什么的不要鸭 (CME is Bad)-第4张图片SoundEngine 中被并发修改的类于是我们确认需要被监视的容器是 field_217942_m(SoundEngine 中的 instanceToChannel),于是我们安装 CMESuckMyDuck-1.0.0.jar 模组,向 Java 虚拟机参数中加入“-javaagent:mods/CMESuckMyDuck-1.0.0.jar=net/minecraft/client/audio/SoundEngine;field_217942_m;Map;nonstatic”,并等待下一次报错。

      最后,打开 CMESuckMyDuck.log 日志,阅读容器修改历史,便可以确认哪几个线程发生了冲突,并发修改了容器导致了崩溃。

      JVM 参数示例

      ConcurrentModificationException 来自 SoundEngine 在 Forge 1.16.5 环境

      -javaagent:mods/CMESuckMyDuck-1.0.0.jar=net/minecraft/client/audio/SoundEngine;field_217942_m;Map;nonstatic

      ConcurrentModificationException 来自 PotionBrewing 在 Forge 1.20.1 环境

      -javaagent:mods/CMESuckMyDuck-1.0.0.jar=net/minecraft/world/item/alchemy/PotionBrewing;f_43494_;List;static

      ArrayIndexOutOfBoundsException 来自 Zeta Mod

      -javaagent:mods/CMESuckMyDuck-1.0.0.jar=org/violetmoon/zetaimplforge/event/ForgeZetaEventBus;convertedHandlers;Map;nonstatic

      其它设置

      日志级别(不推荐修改)

      使用系统属性“-Dcme_suck_my_duck.log_level=<level>”修改日志级别,有 0~3 四个级别。

      • 0 将会输出容器一切访问历史,不仅包括修改,还包括查询如 Map#get、Set#containsAll 等,往往会导致日志过于冗长。

      • 1 将不再输出查询历史,而是仅输出容器的修改历史,是模组默认的日志级别。

      • 2 将不再输出容器修改历史,仅输出向类注入修改时的警告与异常,方便开发者调试。

      • 3 将仅输出模组 premain 阶段的异常。

      ASM API 版本(v1.0.2+)

      为了保持最新版本 Minecraft 的兼容,本模组使用 asm 9.7 版本参与编译。对于旧版 Minecraft 游戏(如 1.12.2),无法应用 ASM_9 等 API 级别的操作,因此玩家需要使用“-Dcme_suck_my_duck.asm_api_version=<version>”修改 ASM API 版本兼容。

      例如对于 1.12.2 游戏,请添加:

      -Dcme_suck_my_duck.asm_api_version=5

      <version> 的默认值为 9。

      文件最大元素数(v1.0.3+)

      由于日志最后几次操作比前面的内容重要得多,因此模组日志在 v1.0.3 之后采取了分页策略,且结束时只保留最终两个页面。每个页面输出的日志数量(即操作调用栈的数量)固定,默认值为 00,玩家可以使用“-Dcme_suck_my_duck.file_max_entries=<size>”修改页面最大元素数。

      构造函数白名单(v1.0.3+)

      有时一个容器所在的类会被应用于很多地方,如 CompoundTag#tags,此时直接使用该模组会导致日志过长,或有效内容被后续操作替换掉。因此玩家可以额外指定构造函数白名单,来使特定模块的对应类中对应的容器被监控。默认为空,即没有白名单,玩家可以使用“-Dcme_suck_my_duck.whitelist_constructor_stacktrace=<str>”来指定。如果容器被构造的调用栈中任何一行包括了白名单字符串的内容,则容器得到监控;否则容器不会被监控,极大地简化了日志输出信息。

    短评加载中..