Skip to content

【崩溃】扫描未加载维度时 HTTP 线程热加载维度,与服务器线程竞争导致崩溃(NPE) #1

Description

@mnaccccs

【崩溃】扫描未加载维度时 HTTP 线程热加载维度,与服务器线程竞争导致崩溃(NPE)

环境

  • GTNH: 2.9.0-beta-1(mod 为 beta-2 构建,如与本问题相关请告知)
  • webapi: 2.9.0-beta2-0.7-pre
  • Minecraft 1.7.10 / Forge 10.13.4.1614 / Java 25.0.2(Oracle)
  • 服务端专用部署(无客户端)

崩溃现象

服务器运行中(已完全启动),通过 Web 界面提交扫描请求后服务器崩溃:

java.lang.NullPointerException: Cannot invoke "it.unimi.dsi.fastutil.longs.LongArrayList.getLong(int)" because "this.wrapped" is null
	at it.unimi.dsi.fastutil.longs.LongOpenHashSet$SetIterator.nextLong(LongOpenHashSet.java:551)
	at net.minecraft.world.gen.ChunkProviderServer.func_73156_b(ChunkProviderServer.java:2589)
	at net.minecraft.world.WorldServer.func_72835_b(WorldServer.java:165)
	at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:625)

crash report 描述为 Exception ticking world,崩溃线程为 Server thread。

日志证据(崩溃前最后一条请求)

[ERROR] [webapi]: [POST]	/gt5/scan?chunkX=-4&chunkZ=-3&dim=180 - Error after 0.122ms
java.lang.RuntimeException: Cannot Hotload Dim: Overworld is not Loaded!
	at net.minecraftforge.common.DimensionManager.initDimension(DimensionManager.java:230)
	at net.minecraft.server.MinecraftServer.func_71218_a(MinecraftServer.java:705)
	at love.shirokasoke.webapi.webserver.handlers.gt5.GT5ChunkScanHandler.handleSubmit(GT5ChunkScanHandler.java:115)

注意这条请求运行在 HTTP 线程池(pool-9-thread-5),而非 Minecraft Server thread。

复现步骤

  1. 服务端完全启动后,先提交一个已加载维度(如主世界 dim=0)的扫描任务(POST /gt5/scan),256 个子任务异步进行中
  2. 扫描未完成时,提交一个当前未加载维度(如 GTNH Personal World dim=180)的扫描请求
  3. 服务器崩溃

原因分析

GT5ChunkScanHandler.handleSubmit 中:

MinecraftServer server = getServer();
WorldServer world = server.worldServerForDimension(dim);   // 在 HTTP 线程执行

这段代码运行在 HTTP 线程上。当 dim 对应的维度未加载时,Forge/GTNH 的 worldServerForDimension 会触发 DimensionManager.initDimension 进行维度热加载,即在非 Server thread 上修改 Minecraft 世界状态(维度表、chunk provider 的 chunk 集合等)。

与此同时 Server thread 正在正常 tick 世界(并且之前提交的扫描任务的 256 个子任务也在 Server thread 队列中执行),两个线程并发操作同一组集合(fastutil LongOpenHashSet),导致 Server thread 在 ChunkProviderServer 迭代 chunk 集合时命中 fastutil 迭代器的 wrapped == null NPE——这是典型的跨线程并发修改特征。

顺带一提:日志中的 Cannot Hotload Dim: Overworld is not Loaded! 并非主世界真的未加载,而是 HTTP 线程跨线程读取世界引用时的可见性问题(读到过期/未同步的引用),同一现象的另一面。

建议修复方向

将维度获取/热加载逻辑放进服务器线程执行,例如把 handleSubmit 中的维度解析与 worldServerForDimension 调用包进 ServerThreadDispatcher.scheduleOnServerThread,或在提交前先在校验阶段用 scheduleOnServerThread 确认维度已加载(未加载则直接返回 4xx,而不是隐式热加载)。扫描任务本身已经是异步投递到 Server thread 的,只是提交阶段的维度解析漏了。

完整 crash report 与日志可提供,如有需要请告知。

Metadata

Metadata

Assignees

Labels

In ProgressIn ProgressbugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions