Add failsafe for low RAM issue.

This commit is contained in:
tom lee
2022-02-04 00:11:53 +08:00
parent 068622895f
commit 95220d4fd7
5 changed files with 47 additions and 7 deletions
@@ -205,6 +205,11 @@ public class LodBuilder
region.isWriting++;
try {
if (region.getMinDetailLevel()!= 0) {
if (!LodUtil.checkRamUsage(0.05, 16)) {
ClientApi.LOGGER.warn("LodBuilder: Not enough RAM avalible for building lods! Skipping...");
return false;
}
LodRegion newRegion = lodDim.getRegionFromFile(region, (byte)0, region.getVerticalQuality());
if (region!=newRegion)
throw new RuntimeException();
@@ -83,6 +83,8 @@ public class BatchGenerator {
generationGroup.updateAllFutures();
if (!MC.hasSinglePlayerServer())
return;
if (!LodUtil.checkRamUsage(0.1, 64)) return;
int eventsCount = generationGroup.getEventCount();
// If we still all jobs running, return.
if (eventsCount >= estimatedPointsToQueue) {
@@ -26,6 +26,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.crypto.spec.GCMParameterSpec;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.enums.config.DropoffQuality;
@@ -316,12 +318,21 @@ public class LodDimension
};
cutAndExpandThread.execute(thread);
}
private boolean expandOrLoadPaused = false;
/** Either expands or loads all regions in the rendered LOD area */
public void expandOrLoadRegionsAsync(int playerPosX, int playerPosZ) {
if (isExpanding) return;
// We have less than 10% or 1MB ram left. Don't expend.
if (expandOrLoadPaused && !LodUtil.checkRamUsage(0.4, 512)) {
//ClientApi.LOGGER.info("Not enough ram for expandOrLoadThread. Skipping...");
return;
} else if (expandOrLoadPaused) {
ClientApi.LOGGER.info("Enough ram for expandOrLoadThread. Restarting...");
}
isExpanding = true;
expandOrLoadPaused = false;
VerticalQuality verticalQuality = CONFIG.client().graphics().quality().getVerticalQuality();
DropoffQuality dropoffQuality = CONFIG.client().graphics().quality().getDropoffQuality();
@@ -333,9 +344,19 @@ public class LodDimension
// for the same location
Runnable thread = () -> {
//ClientApi.LOGGER.info("LodDim expend Region: " + playerPosX + "," + playerPosZ);
Pos minPos = regions.getMinInRange();
iterateWithSpiral((int x, int z) -> {
if (expandOrLoadPaused) return;
if (!LodUtil.checkRamUsage(0.1, 32)) {
Runtime.getRuntime().gc();
if (!LodUtil.checkRamUsage(0.2, 64)) {
ClientApi.LOGGER.warn("Not enough ram for expandOrLoadThread. Pausing until Ram is freed...");
// We have less than 10% or 1MB ram left. Don't expend.
expandOrLoadPaused = true;
saveDirtyRegionsToFile(false);
return;
}
}
int regionX;
int regionZ;
LodRegion region;
@@ -355,8 +376,8 @@ public class LodDimension
playerPosZ);
minDetail = DetailDistanceUtil.getDetailLevelFromDistance(minDistance);
maxDetail = DetailDistanceUtil.getDetailLevelFromDistance(maxDistance);
boolean updated = false;
boolean expended = false;
if (region == null) {
region = getRegionFromFile(regionPos, minDetail, verticalQuality);
regions.set(regionX, regionZ, region);
@@ -56,6 +56,7 @@ public class DetailDistanceUtil
maxDistance = CONFIG.client().graphics().quality().getLodChunkRenderDistance() * 16 * 8;
}
/*// Need UPDATE and BUG FIX
public static int baseDistanceFunction(int detail)
{
if (detail <= minGenDetail)
@@ -79,11 +80,11 @@ public class DetailDistanceUtil
public static int getDrawDistanceFromDetail(int detail)
{
return baseDistanceFunction(detail);
}
}*/
public static byte baseInverseFunction(int distance, byte minDetail)
{
byte detail;
int detail;
distance -= minDetailDistance;
if (distance < 0 || CONFIG.client().graphics().advancedGraphics().getAlwaysDrawAtMaxQuality())
@@ -92,12 +93,12 @@ public class DetailDistanceUtil
double scaledDistance = distance;
scaledDistance /= distanceUnit;
if (CONFIG.client().graphics().quality().getHorizontalQuality() == HorizontalQuality.LOWEST)
detail = (byte) (scaledDistance);
detail = (int) (scaledDistance);
else
{
double base = CONFIG.client().graphics().quality().getHorizontalQuality().quadraticBase;
double logBase = Math.log(base);
detail = (byte) (Math.log(scaledDistance) / logBase);
detail = (int) (Math.log(scaledDistance) / logBase);
}
return (byte) LodUtil.clamp(minDetail, detail+minDetail, maxDetail - 1);
}
@@ -434,4 +434,15 @@ public class LodUtil
numb = Float.intBitsToFloat(i);
return numb * (1.5F - half * numb * numb);
}
// True if the requested threshold pass, or false otherwise
// For details, see:
// https://stackoverflow.com/questions/3571203/what-are-runtime-getruntime-totalmemory-and-freememory
public static boolean checkRamUsage(double minFreeMemoryPercent, int minFreeMemoryMB) {
long freeMem = Runtime.getRuntime().freeMemory() + Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory();
if (freeMem < minFreeMemoryMB * 1024 * 1024) return false;
long maxMem = Runtime.getRuntime().maxMemory();
if (freeMem/(double)maxMem < minFreeMemoryPercent) return false;
return true;
}
}