在找崩溃报告之前,先看看你是不是有这样泥土芳香的背景:
"要使用xxx mod,你必须安装正常的依赖项,要求xxx mod xxx版本或更高版本(缺失)“,这时候请百度/curseforge搜索那个缺失的mod(如图中bdlib),不要四处乱问我这个怎么开不起来,你前置mod都没有啊。
Minecraft是个很玄学的游戏,就算你什么模组也不加,玩个原版都有可能崩溃,无非是比有模组时少罢了。正如酒石酸所说:发生崩溃时如果找不到崩溃报告,就说“我崩溃了怎么办”,还不如上街找个算命先生算算为什么崩溃好些,那么在哪里找它们呢?
打开你的MC安装目录(一般为.minecraft文件夹,部分整合包的根目录与整合包同名,比如all the mods,但无论名字有什么不同,它都是mods和saves的所在),找到crash-report文件夹,将内部日期最新(即为你最近的一个崩溃报告)的文件,用记事本或者notepad++打开,就可以看到崩溃信息了。这个文章主要讲的是forge的崩溃报告——其实原版也是一样的道理,只不过它的形式应该是aac.abb.b这样的形式,根本读不出来,forge的崩溃报告相当于把它变成了人类可读形式。
(一个崩溃报告文件夹的长相)
现在我们随便找一个崩溃报告来看看它的结构。
http://paste.ubuntu.com/25672422/(看这里看这里!)
第28行以前“coremods are present”都是废话——首先要解释下什么是coremod。
有一些不怎么安分的作者,会用asm/mixin和forge自带的access transformer等工具修改原版代码,这些影响到MC底层的mod(更准确来说是打mod行为),就是所谓的coremod了。
现实中coremod导致崩溃的概率并不高,但是它的存在可能会误导玩家的判断,因此1.1x之后,forge崩溃报告都会把游戏中出现的coremod罗列出来,有一种“死马当活马医我给你写出来了别怪我没说”的意思,大多数情况下,这些coremod都可以忽略。
重要信息在31行之后,我们挨个读:
description:rendering item翻译过来是“故障描述:渲染物品”,但是,渲染的是哪个物品?
java.lang.ClassCastException: net.minecraft.item.ItemAir cannot be cast to net.minecraft.item.ItemBlock at twilightforest.block.ColorHandler.lambda$init$13(ColorHandler.java:266)
接下来两行的内容:
java.lang.ClassCastException——这是java.lang包的ClassCastException(转型异常),有必要说明的是,并不是所有的异常(Exception)都会导致崩溃,错误(Error)才会,关键在于Java虚拟机(JVM)能不能处理这玩意。
(
net.minecraft.item.ItemAir——net作为最上级的目录,含义并不重要;minecraft就是MC本体了,item代指物品,ItemAir代表空气——MC的空格并不是什么都没有,而是一个叫空气的物品取代了那里,同样,在MC的天空中也不是什么都没有,而是“空气方块”。
cannot cast to xxx:不能变成……什么呢?
net.minecraft.item.ItemBlock:结构和上面那个ItemAir一样,不过是“不能变成一个ItemBlock”——什么是ItemBlock?
如果你从创造栏里拿出一个方块,你会发现它和一般的物品区别只在于,可以放到世界中变成真正的方块——没错,这就是ItemBlock,一个方块的物品存在形式,如果你把手中的物品丢到世界中(无论它是一般的Item还是ItemBlock),那么掉落物属于EntityItem,也就是说,这时物品以实体的形式存在,因此掉落物可以被kill @e 指令消除。
如果你足够细心,会发现net,minecraft,item这三级目录都是小写的,而ItemBlock是每个单词首字母大写(所谓大写驼峰式),这是因为前三级目录都是package(包),只有ItemBlock是class(类),负责具体的实现。
连起来读就是:“一个空气物品(在玩家物品栏中)转变为某个方块时,java.lang包抛出异常。”
java.lang是Java之下最基础的包之一,难道这玩意还坏了?当然不是,让我们看下一行。
at twilightforest.block.xxx——看到这里其实应该松一口气,因为twilight forest就是暮色森林啦,在这儿基本就可以确定是暮色崩溃了。
(分割线警告)
那么下面的一大堆at at at又是什么呢?这要知道什么是栈帧(stacktrace)。
CPU寄存器的空间是极其有限的,因此方法的调用需要在栈上开辟空间,每调用一个方法就会生成一个栈帧,因此崩溃报告里的一堆at at at所代表的一系列栈帧,某种意义上是一条调用链,最后被调用的方法(也就是爆出异常的方法)会被崩溃报告放在最上面,如下:
- at twilightforest.block.ColorHandler.lambda$init$13(ColorHandler.java:266) //最顶的栈帧,最后发生异常就在这里,异常会被沿着调用链逐级抛出直到最上层无法被处理)
- at net.minecraft.client.renderer.color.ItemColors.func_186728_a(ItemColors.java:139)
- at mod.chiselsandbits.render.helpers.ModelUtil.getItemStackColor(ModelUtil.java:466) //chiselandbits指雕刻工艺mod,当时的情况与其无关
- at mod.chiselsandbits.client.ItemColorPatterns.func_186726_a(ItemColorPatterns.java:28)
- at net.minecraft.client.renderer.color.ItemColors.func_186728_a(ItemColors.java:139)
- at net.minecraft.client.renderer.RenderItem.func_175032_a(RenderItem.java:315) //MC原版渲染物品方法
- at net.minecraft.client.renderer.RenderItem.func_175045_a(RenderItem.java:168)
- at net.minecraft.client.renderer.RenderItem.func_175036_a(RenderItem.java:140)
- at net.minecraft.client.renderer.RenderItem.func_180454_a(RenderItem.java:203)
- at net.minecraft.client.renderer.RenderItem.func_184390_a(RenderItem.java:475)
- at net.minecraft.client.renderer.RenderItem.func_184391_a(RenderItem.java:517)
- at codechicken.lib.render.item.CCRenderItem.func_184391_a(CCRenderItem.java:223) //codechickenlib,一个渲染相关的类库,用其做前置可以避免写大量材质与模型相关的json,但是也引发了不少崩溃,属于“重要而麻烦”的东西
- at codechicken.lib.render.item.CCRenderItem.func_180450_b(CCRenderItem.java:208)
- at net.minecraft.client.gui.inventory.GuiContainerCreative.func_147051_a(GuiContainerCreative.java:880)
- at net.minecraft.client.gui.inventory.GuiContainerCreative.func_146976_a(GuiContainerCreative.java:716)
- at net.minecraft.client.gui.inventory.GuiContainer.func_73863_a(GuiContainer.java:76)
- at net.minecraft.client.renderer.InventoryEffectRenderer.func_73863_a(InventoryEffectRenderer.java:51)
- at net.minecraft.client.gui.inventory.GuiContainerCreative.func_73863_a(GuiContainerCreative.java:604)
- at net.minecraftforge.client.ForgeHooksClient.drawScreen(ForgeHooksClient.java:382) //forge给原版绘制屏幕的画面打的钩子
- at sun.reflect.GeneratedMethodAccessor34.invoke(Unknown Source)
- at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
- at java.lang.reflect.Method.invoke(Unknown Source) //Java反射调用方法
- at Reflector.callVoid(Reflector.java:547)
- at net.minecraft.client.renderer.EntityRenderer.func_181560_a(EntityRenderer.java:1433)
- at net.minecraft.client.Minecraft.func_71411_J(Minecraft.java:1077)
- at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:372)
- at net.minecraft.client.main.Main.main(SourceFile:124) //MC客户端的main方法,MC在这里启动
- at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
- at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
- at java.lang.reflect.Method.invoke(Unknown Source)
- at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
- at net.minecraft.launchwrapper.Launch.main(Launch.java:28) //launchwrapper的main方法,在这里控制MC的运行
(分割线结束)
当然我们也不能把暮色一删了事,看看能不能抢救呢?
twilightforest.block.ColorHandler.lambda$init$13(ColorHandler.java:266)
我们可以结合暮色的GitHub代码来看这一条:https://github.com/TeamTwilight/ ... k/ColorHandler.java(这是1.11的暮色,curseforge上是下载不到的)
看到了吗?崩溃报告的原句是twilightforest.block.ColorHandler,代表崩溃发生在twilightforest下面的block包中的ColorHandler类,与上面的GitHub代码地址形成对应。
java:266代表着这个类文件的第266行,那我们可以看看这个266行发生了什么:
itemColors.registerItemColorHandler((stack, tintIndex) -> blockColors.colorMultiplier(((ItemBlock)stack.getItem()).getBlock().getStateFromMeta(stack.getMetadata()), null, null, tintIndex), TFBlocks.auroraBlock, TFBlocks.auroraPillar, TFBlocks.auroraSlab, TFBlocks.auroraDoubleSlab, TFBlocks.darkleaves, TFBlocks.giantLeaves, TFBlocks.fireJet, TFBlocks.magicLeaves, TFBlocks.leaves, TFBlocks.leaves3, TFBlocks.plant, TFBlocks.castleMagic, TFBlocks.castleDoor, TFBlocks.castleDoorVanished);
lambda$init$13里的lambda代表lambda表达式,也就是上面的那个->符号,结合ItemBlock,我们可以看到问题的原因在于——如果玩家的物品栏什么都没有,那么stack(ItemStack)应该是空的,根本不能从stack获取到Item,还转什么ItemBlock?
当然,看是一回事,自己动手做又是一回事,绝大多数人连看都看不到这里,如果你不会开发,还是老老实实的向作者发issue报告问题吧:
http://www.mcbbs.net/thread-787619-1-1.html(大多数作者都会把mod源码放在github上,少部分会放在bitbucket,gitlab之类源码托管网站,操作大同小异)
- at mod.chiselsandbits.render.helpers.ModelUtil.getItemStackColor(ModelUtil.java:466)
- //还记得刚才说到的雕刻工艺吗?
- at mod.chiselsandbits.client.ItemColorPatterns.func_186726_a(ItemColorPatterns.java:28)
73行以后里面的信息与先前的基本一样,没啥可看。
121行:affected level(影响范围)
主要是第129行所代表的内容level spawn location:代表着崩溃发生的具体位置和区块,无法修复时可以用worldedit(创世神插件),MCEdit,NBTExplorer之类编辑器删除掉这一方块/区块。
World: (-28,64,256), (玩家所在点-28,64,256)
Chunk: (at 4,4,0 in -2,16; contains blocks -32,0,256 to -17,255,271), (区块-2,16,区块内部坐标4,4,0,包括了-32,0,256到-17,255,271坐标的方块)Region: (-1,0; contains chunks -32,0 to -1,31, blocks -512,0,0 to -1,255,511)(区域:包括了-32,0到-1,31这一大片区块,没啥用处)
151行system details之后是你的系统详情,包括你的系统,Java版本,内存,安装了哪些模组等等。
Minecraft Version: 1.11.2 (MC版本1.11.2)
Operating System: Windows 10 (amd64) version 10.0(操作系统Windows 10 64位,一般与MC的崩溃没有关系,以后问崩溃的时候不用说你是哪个系统,除非是winxp这种山村老尸)
Java Version: 1.8.0_144, Oracle Corporation(Java版本:1.8.0_144,较新的版本,如果是Java 1.8.0_60,25甚至是Java 7这样的旧版本请更新)
Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode),Oracle Corporation Memory: 594339048 bytes (566 MB) / 2823290880 bytes (2692 MB) up to 5324144640 bytes (5077 MB) (当前内存占用,最大可以有5077MB)
JVM Flags: 5 total; -XX:+UseParallelGC -XX:-UseGCOverheadLimit -XX:-OmitStackTraceInFastThrow -Xmn128m -Xmx5120m(Java虚拟机参数,一般都是默认参数启动的,不需要担心)
UCHIJAAAA:代表forge mod的不同加载阶段。
- States: 'U' = Unloaded //mod未加载,越往下时间越靠后,E则可能对应任何一个阶段
- 'L' = Loaded //mod已加载(少见于崩溃报告中,可以忽略),这两个阶段往往在MC窗口出现前后
- 'C' = Constructed //mod已经构建,对应forge加载1/7阶段
- 'H' = Pre-initialized //mod预初始化,对应forge加载2/7阶段
- 'I' = Initialized //mod初始化,对应forge加载2/7阶段后半截
- 'J' = Post-initialized //mod后初始化,对应forge加载4/7阶段
- 'A' = Available //mod可用状态,对应forge加载5,6/7阶段,如果有不止一个A,说明游戏已经启动
- 'D' = Disabled //mod被禁用,一般被禁用的mod并不会触发崩溃
- 'E' = Errored //mod出错
347行之后:
- Loaded coremods (and transformers):
- Default Options (DefaultOptions_1.11.2-8.2.2.jar)
- net.blay09.mods.defaultoptions.coremod.DefaultOptionsClassTransformer
- ForgelinPlugin (Forgelin-1.5.1.jar)
-
- Do not report to Forge! Remove FoamFixAPI (or replace with FoamFixAPI-Lawful) and try again. (foamfix-0.6.3-anarchy.jar)
(如果想进一步了解coremod,可以查看xfl03的教程、liach的教程和我的教程。)
394行以下到最后可以视作废话。
这一篇我们来看一看一些常见的异常。
http://paste.ubuntu.com/25678716/ (看这里看这里!)
28行以前的coremod are present依旧是废话。
35行异常:java.lang.RuntimeException: java.lang.NullPointerException,即为空指针异常,空指针异常就是该对象没有被正确初始化(为空)时的引用异常——我们都是单身狗对吧,哪里找对象给你引用去?没有对象,自然很崩溃啦。
55-57行:
caused by:java.lang.NullPointerExceptionat mapwriter.BlockColourGen.genBlockColours(BlockColourGen.java:176)
at mapwriter.Mw.reloadBlockColours(Mw.java:289)
结合上面的原理,我们可以确定是mapwriter(一个小地图mod)之下的BlockColourGen类异常,由字面意思很容易读出,这是地图在生成方块颜色(genBlockColours)时出现的错误。
以上没对象什么的,只是个形象比喻,普通玩家不需要知道原理,因为这种崩溃一般发生在某一特定事件被触发,比如挖掉某根管道啦,从箱子/储物桶中拿取物品啦,要骑上某匹被诅咒的马啦……
说解决也简单,避开引发崩溃的事件(例如玩家交互,破坏方块,实体死亡之类),例如用管道或者线缆,或者假玩家(比如Extra Utilities 2的mechanical user以及各种挖矿机,都是虚拟出来的假玩家)代替玩家进行资源获取与物流;例如把出故障的实体打掉(如果是打掉时出了问题就先留着);例如不进入进而删除故障区块——总之,别啥崩溃你非得干啥,这不是欠的吗?同时到作者的GitHub源码库下提出issue,等待修复。
以下均可以根据上文所讲述原理,对应上崩溃原因。
好,让我们看看下一个,应该说是一类崩溃:发生在游戏启动前(窗口没出现)的崩溃,这种崩溃是不会生成crash-report的,但是所有的信息都会在fml-cilent-latest.log下显示(HMCL等启动器的日志即对应这个文件),处在MC目录(.minecraft)下的logs文件夹中,一般都是八云紫的裹脚布——又臭又长,仅适合开发者使用(除非游戏没开启就崩溃,否则请不要把这堆玩意给复制出来!),但它确实是最完整的信息,即使是crash report,也只是从这个日志中提取了崩溃时发生的错误,但是也足够了。
由于没开启就崩溃,日志不会很长,一般导致崩溃的是如下几个原因:
libraries(库文件)下载不完全:一般是网络问题导致的,日志中会显示“scala”“log4j”这样的字符,这种情况可以更换启动器的下载源(例如HMCL启动器,启动器设置-下载源中将官方换成bangbang93),开启VPN(科学上网),或者直接跟别人要个现成的libraries文件夹并在启动器里开启“不使用公共路径”。
有的时候会报出ClassNotFoundException,可以先重启,如果是第一次开整合包,建议重下forge。
Java,显卡驱动,高清修复等问题:前两者都是MC运行的基本盘,Java版本过旧容易引发问题,1.12更是强制使用Java 8;显卡驱动也有影响,曾经的NVIDIA的378.49驱动直接无差别引发了MC的崩溃;高清修复虽然不是,但是它相当程度修改了原版代码,加上它bug多还不开源,一直受人诟病。还有一些古董级电脑,其显卡连OpenGL都无法支持的,还是趁早砸电脑吧。
一些coremod引发的崩溃:这种崩溃其实非常少见,没有水平足够的技术,不要随便怀疑。
下一个崩溃类型:没有有价值信息的玄学崩溃
http://paste.ubuntu.com/25679329/(看这里看这里!)
java.lang.IndexOutOfBoundsException: Index: 416, Size: 416,意为“数组越界”,这就很头疼了,我玩的好好的哪来的越界? 当然这多半是傻缺作者分不清数组长度与数组索引之间的区别(数组地址是从0开始的),或者因为粗心弄到了非法的索引(例如负数索引,又或者是一个空List里面想要获取某个位置上的数据),不过这和普通玩家又有什么关系?
下面几行,如at java.util.ArrayList.rangeCheck(Unknown Source)at java.util.ArrayList.remove(Unknown Source),单从报告本身是看不出具体哪个mod(大概率是原版自己)引发的越界崩溃。
不过这种崩溃,来得突然去得也快,发生之后,首先重启,重启好了自然可以继续玩下去;如果重启也失败,试着找回原来备份的存档并替换原来的存档(推荐使用FTB Utilities或者Aroma Backup自动备份),如果找不到任何有价值的备份,只能删区块删存档了。
下一个崩溃类型:模组冲突引发的崩溃
现在的主流模组,尤其是欧美系的EU啊,RF啊等模组,稳定性都没啥说,但日系模组(如slashblade,就是拔刀剑)bug很多,不够稳定,崩溃报告里如果出现这样的模组,想想是不是该删模组了,尤其是reika kalseki的mod(其前置为dragon api),更是大多数1.7mod包崩溃的元凶。
当然欧美系内部也有出事的,比如下面的崩溃:http://paste.ubuntu.com/25679409/(看这里看这里!)
at com.creativemd.creativecore.common.world.WorldChunkedTileEntityList.get(WorldChunkedTileEntityList.java:162)
at com.creativemd.creativecore.common.world.WorldChunkedTileEntityList.get(WorldChunkedTileEntityList.java:21)
- @Override
- public TileEntity get(int paramInt) {
- // Ouch this should not happen, bad performance can be expected!!!
-
-
- /*int currentIndex = 0;
- for (Iterator<ArrayList<TileEntity>> iterator = content.getValues().iterator(); iterator.hasNext();) {
- ArrayList<TileEntity> type = iterator.next();
- if(currentIndex + type.size() < paramInt)
- currentIndex += type.size();
- else
- return type.get(paramInt-currentIndex);
- }
-
- return null;*/
-
- throw new RuntimeException("Please use the iterator instead");
(这个类和报告中的embers mod相应方法已经不复存在,只能怀古一下了)
如果发现NoSuchMethodError,请检查是不是自己的forge和mod版本太旧了或者不匹配(已知forge 1.12.2-2768以上一些版本,因为PotionHelper类的变动,引发了一系列mod崩溃)
玩家在选择模组的时候,要尽可能选择欧美系作者(他们的模组一般搭载在curseforge上)的著名模组,比如Ender IO(末影接口)的玄钢斧,Draconic Evolution(龙之进化)的神龙斧,Tinker's Construct(匠魂)的伐木斧,Gregtech(格雷科技)的斧头,Botania(植物魔法)的泰拉斧,Mekanism(通用机械)的原子分解机,个个都有连锁范围砍树功能,干嘛多装一个砍树模组?
模组挑选可以参考此贴:https://tieba.baidu.com/p/5297039388
小结:面对崩溃时,你或许要准备好这些:
重启游戏(可以解决一半以上的问题);
更新Java,显卡驱动,optifine(如果你有的话);
VanillaFix mod:这个mod可以阻止你彻底崩掉游戏(仅仅是退出当前世界),并会自动将你的崩溃报告上传,生成链接在一个同样泥土芳香的界面中,只需要复制链接给懂的人看就行了。
搞清楚你包里的模组特性,更新/卸载报告里提到的异常模组。(并不推荐卸载,如果不卸载服务器就开不下去另说)
一个WE(创世神)插件或者其他的手段以变更出错的区块或方块;
已经备份的近期存档;
一颗冷静的心。
我们可以随便找一个spigot的timings(时间监测报告)来看看:https://timings.aikar.co/?id=9e95d6b64bb9462083458e978c4aee65
将其展开,不难看出Minecraft的tickEntity方法调用耗时最大(都变红了),从字面意思来看,是实体(entity)在计时(tick)的时候卡顿。
其中占用最高的还是EntityVillager(村民),总延迟296.318s,占用95%的tick时长。
其他类似的timings都可以结合上述原理,找到耗时最高的方法,确定卡顿的罪魁祸首——无论是spigot还是sponge,反混淆出的名字都是可读的,猜字面意思即可。