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

距离显示结果还剩4票~

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

历史编辑记录更多
    管理组

      暂无管理组..

    编辑组

      暂无编辑组..

    最近参与编辑
    活跃
    开源

    并发修改什么的不要鸭

    CME is Bad

    • 摘要

      在玩大型整合包的时候,常常会遇到并发修改异常(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_)。

      对于 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 from SoundEngine in Forge 1.16.5 Environment

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

      ConcurrentModificationException from PotionBrewing in Forge 1.20.1 Environment

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

      ArrayIndexOutOfBoundsException from 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 阶段的异常。

    短评加载中..