fix(phase): payload 相位等待期间维度线程跳过 playerPacketQueue.drain,断 getChunk 死锁链
死锁现场(threaddump):主线程在 MainThreadPhaseCoordinator.run 的 managedBlock 自旋, 等所有维度 isTicking()==false;overworld 唯一在 tick,栈: drainChunkTasks:277 -> PlayerPacketQueue.drain -> ServerboundMovePlayerPacket.handle -> Entity.move -> BlockGetter.clip(碰撞射线) -> getBlockState -> getChunk(未加载) -> ServerChunkCache.getChunk:159 -> mainThreadProcessor.managedBlock park 等区块生成。 两方互等:主线程等维度停;维度等区块 future;future 推进需主线程 poll,而主线程在等维度停。 修复:drainChunkTasks 调 playerPacketQueue.drain() 前检查 MainThreadPhaseCoordinator.blocksWorkerStart(server)——主线程正在相位等待时跳过本轮移动包处理, 让维度尽快收口、主线程相位尽快通过;包不丢(留队列),下一拍主线程不再等时再处理。 本次也回退 ChunkPrefetcher 深度/扇面(实测加深反而下降)。
This commit is contained in:
1 parent
1ab215dc72
commit
1702d11d8f
2 files changed
+12
-6
No files matched your search
@@ -48,12 +48,12 @@ public final class ChunkPrefetcher {
|
||||
/** 预取重算间隔(tick),降低每个玩家的逐 tick 开销。 */
|
||||
private static final int PREFETCH_INTERVAL_TICKS = 5;
|
||||
|
||||
/** 预取深度:在玩家视距之外,再向前预取的区块数。冲刺进入大片新区块时,生成速度是瓶颈,
|
||||
* 加深到 10 格给生成管线更多提前量(沿已生成边缘几乎无额外开销:hasChunk 命中即跳过)。 */
|
||||
private static final int PREFETCH_DEPTH = 10;
|
||||
/** 预取深度:在玩家视距之外,再向前预取的区块数(收敛为 4~6 格,避免过度预取浪费算力)。
|
||||
* 实测:加深到 10 + 扇面反而下降——生成管线吞吐有限,远处预取票挤占近处生成,故保持 6。 */
|
||||
private static final int PREFETCH_DEPTH = 6;
|
||||
|
||||
/** 预取扇面半宽:除正前方外,额外预取左右各 ±1 列(覆盖拐弯/斜向移动)。 */
|
||||
private static final int PREFETCH_FAN_HALF = 1;
|
||||
/** 预取扇面半宽:0 = 仅正前方一条线(实测加宽反而拖慢,保持 0)。 */
|
||||
private static final int PREFETCH_FAN_HALF = 0;
|
||||
|
||||
/** 自定义预取 ticket:FULL 级别 + 有限存活时间。 */
|
||||
private static final TicketType<Unit> PREFETCH_TICKET =
|
||||
|
||||
@@ -274,7 +274,13 @@ public final class LevelTickLoop implements Runnable, java.util.concurrent.Execu
|
||||
continue; // 有就绪任务,继续排空
|
||||
}
|
||||
// 区块任务空档期补排空一次玩家包(移动/交互等非命令包),减轻其在高负载下的延迟。
|
||||
((IPlayerPacketQueue) this.level).modzuozhi$playerPacketQueue().drain();
|
||||
// 但主线程正在相位等待(payload 独占等所有维度停)时跳过:移动包 handle 会做实体移动
|
||||
// 碰撞检测 → getChunk(未加载) → mainThreadProcessor.managedBlock park 等区块生成,
|
||||
// 而此刻主线程正等本维度停、无人推进生成 → 维度 tick 收口被卡住 → 主线程等 10s+ 死锁。
|
||||
// 包不丢(留在队列),下一拍(主线程不再等)再处理。
|
||||
if (!dev.modzuozhi.core.compat.MainThreadPhaseCoordinator.blocksWorkerStart(this.level.getServer())) {
|
||||
((IPlayerPacketQueue) this.level).modzuozhi$playerPacketQueue().drain();
|
||||
}
|
||||
if (overBudget) {
|
||||
break; // 超预算窗口内不可忙等,避免继续占用 worker
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user