在 SystemInfo 中采集内存信息 (#3903)

This commit is contained in:
Glavo
2025-05-10 12:06:11 +08:00
committed by GitHub
parent 1da98d6d67
commit 48ca2d6ee6
24 changed files with 483 additions and 200 deletions

View File

@@ -45,6 +45,7 @@ import org.jackhuang.hmcl.util.platform.SystemInfo;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.net.CookieHandler; import java.net.CookieHandler;
import java.net.CookieManager; import java.net.CookieManager;
import java.nio.file.Files; import java.nio.file.Files;
@@ -55,6 +56,7 @@ import java.util.Collections;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX; import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -247,13 +249,17 @@ public final class Launcher extends Application {
LOG.info("HMCL Current Directory: " + Metadata.HMCL_CURRENT_DIRECTORY); LOG.info("HMCL Current Directory: " + Metadata.HMCL_CURRENT_DIRECTORY);
LOG.info("HMCL Jar Path: " + Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found")); LOG.info("HMCL Jar Path: " + Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found"));
LOG.info("HMCL Log File: " + Lang.requireNonNullElse(LOG.getLogFile(), "In Memory")); LOG.info("HMCL Log File: " + Lang.requireNonNullElse(LOG.getLogFile(), "In Memory"));
LOG.info("Memory: " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "MB"); LOG.info("JVM Max Memory: " + MEGABYTES.formatBytes(Runtime.getRuntime().maxMemory()));
LOG.info("Physical Memory: " + OperatingSystem.TOTAL_MEMORY + " MB"); try {
LOG.info("Metaspace: " + ManagementFactory.getMemoryPoolMXBeans().stream() for (MemoryPoolMXBean bean : ManagementFactory.getMemoryPoolMXBeans()) {
.filter(bean -> bean.getName().equals("Metaspace")) if ("Metaspace".equals(bean.getName())) {
.findAny() long bytes = bean.getUsage().getUsed();
.map(bean -> bean.getUsage().getUsed() / 1024 / 1024 + "MB") LOG.info("Metaspace: " + MEGABYTES.formatBytes(bytes));
.orElse("Unknown")); break;
}
}
} catch (NoClassDefFoundError ignored) {
}
LOG.info("Native Backend: " + (NativeUtils.USE_JNA ? "JNA" : "None")); LOG.info("Native Backend: " + (NativeUtils.USE_JNA ? "JNA" : "None"));
if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) { if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) {
LOG.info("XDG Session Type: " + System.getenv("XDG_SESSION_TYPE")); LOG.info("XDG Session Type: " + System.getenv("XDG_SESSION_TYPE"));

View File

@@ -40,6 +40,7 @@ import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.java.JavaRuntime; import org.jackhuang.hmcl.java.JavaRuntime;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.SystemInfo;
import org.jackhuang.hmcl.util.versioning.VersionNumber; import org.jackhuang.hmcl.util.versioning.VersionNumber;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -383,7 +384,7 @@ public class HMCLGameRepository extends DefaultGameRepository {
.setOverrideJavaArguments(StringUtils.tokenize(vs.getJavaArgs())) .setOverrideJavaArguments(StringUtils.tokenize(vs.getJavaArgs()))
.setMaxMemory(vs.isNoJVMArgs() && vs.isAutoMemory() ? null : (int)(getAllocatedMemory( .setMaxMemory(vs.isNoJVMArgs() && vs.isAutoMemory() ? null : (int)(getAllocatedMemory(
vs.getMaxMemory() * 1024L * 1024L, vs.getMaxMemory() * 1024L * 1024L,
OperatingSystem.getPhysicalMemoryStatus().getAvailable(), SystemInfo.getPhysicalMemoryStatus().getAvailable(),
vs.isAutoMemory() vs.isAutoMemory()
) / 1024 / 1024)) ) / 1024 / 1024))
.setMinMemory(vs.getMinMemory()) .setMinMemory(vs.getMinMemory())

View File

@@ -63,6 +63,7 @@ import java.util.stream.Collectors;
import static javafx.application.Platform.runLater; import static javafx.application.Platform.runLater;
import static javafx.application.Platform.setImplicitExit; import static javafx.application.Platform.setImplicitExit;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX; import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
import static org.jackhuang.hmcl.util.Lang.resolveException; import static org.jackhuang.hmcl.util.Lang.resolveException;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
@@ -553,8 +554,9 @@ public final class LauncherHelper {
} }
// Cannot allocate too much memory exceeding free space. // Cannot allocate too much memory exceeding free space.
if (OperatingSystem.TOTAL_MEMORY > 0 && OperatingSystem.TOTAL_MEMORY < setting.getMaxMemory()) { long totalMemorySizeMB = (long) MEGABYTES.convertFromBytes(SystemInfo.getTotalMemorySize());
suggestions.add(i18n("launch.advice.not_enough_space", OperatingSystem.TOTAL_MEMORY)); if (totalMemorySizeMB > 0 && totalMemorySizeMB < setting.getMaxMemory()) {
suggestions.add(i18n("launch.advice.not_enough_space", totalMemorySizeMB));
} }
VersionNumber forgeVersion = analyzer.getVersion(LibraryAnalyzer.LibraryType.FORGE) VersionNumber forgeVersion = analyzer.getVersion(LibraryAnalyzer.LibraryType.FORGE)

View File

@@ -29,7 +29,7 @@ import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.javafx.ObservableHelper; import org.jackhuang.hmcl.util.javafx.ObservableHelper;
import org.jackhuang.hmcl.util.javafx.PropertyUtils; import org.jackhuang.hmcl.util.javafx.PropertyUtils;
import org.jackhuang.hmcl.java.JavaRuntime; import org.jackhuang.hmcl.java.JavaRuntime;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.SystemInfo;
import org.jackhuang.hmcl.util.versioning.GameVersionNumber; import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import java.io.IOException; import java.io.IOException;
@@ -39,6 +39,7 @@ import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/** /**
@@ -47,7 +48,16 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
@JsonAdapter(VersionSetting.Serializer.class) @JsonAdapter(VersionSetting.Serializer.class)
public final class VersionSetting implements Cloneable, Observable { public final class VersionSetting implements Cloneable, Observable {
private transient ObservableHelper helper = new ObservableHelper(this); private static final int SUGGESTED_MEMORY;
static {
double totalMemoryMB = MEGABYTES.convertFromBytes(SystemInfo.getTotalMemorySize());
SUGGESTED_MEMORY = totalMemoryMB >= 32768
? 8192
: Integer.max((int) (Math.round(totalMemoryMB / 4.0 / 128.0) * 128), 256);
}
private final transient ObservableHelper helper = new ObservableHelper(this);
public VersionSetting() { public VersionSetting() {
PropertyUtils.attachListener(this, helper); PropertyUtils.attachListener(this, helper);
@@ -219,7 +229,7 @@ public final class VersionSetting implements Cloneable, Observable {
permSizeProperty.set(permSize); permSizeProperty.set(permSize);
} }
private final IntegerProperty maxMemoryProperty = new SimpleIntegerProperty(this, "maxMemory", OperatingSystem.SUGGESTED_MEMORY); private final IntegerProperty maxMemoryProperty = new SimpleIntegerProperty(this, "maxMemory", SUGGESTED_MEMORY);
public IntegerProperty maxMemoryProperty() { public IntegerProperty maxMemoryProperty() {
return maxMemoryProperty; return maxMemoryProperty;
@@ -734,7 +744,7 @@ public final class VersionSetting implements Cloneable, Observable {
obj.addProperty("javaArgs", src.getJavaArgs()); obj.addProperty("javaArgs", src.getJavaArgs());
obj.addProperty("minecraftArgs", src.getMinecraftArgs()); obj.addProperty("minecraftArgs", src.getMinecraftArgs());
obj.addProperty("environmentVariables", src.getEnvironmentVariables()); obj.addProperty("environmentVariables", src.getEnvironmentVariables());
obj.addProperty("maxMemory", src.getMaxMemory() <= 0 ? OperatingSystem.SUGGESTED_MEMORY : src.getMaxMemory()); obj.addProperty("maxMemory", src.getMaxMemory() <= 0 ? SUGGESTED_MEMORY : src.getMaxMemory());
obj.addProperty("minMemory", src.getMinMemory()); obj.addProperty("minMemory", src.getMinMemory());
obj.addProperty("autoMemory", src.isAutoMemory()); obj.addProperty("autoMemory", src.isAutoMemory());
obj.addProperty("permSize", src.getPermSize()); obj.addProperty("permSize", src.getPermSize());
@@ -801,8 +811,8 @@ public final class VersionSetting implements Cloneable, Observable {
return null; return null;
JsonObject obj = (JsonObject) json; JsonObject obj = (JsonObject) json;
int maxMemoryN = parseJsonPrimitive(Optional.ofNullable(obj.get("maxMemory")).map(JsonElement::getAsJsonPrimitive).orElse(null), OperatingSystem.SUGGESTED_MEMORY); int maxMemoryN = parseJsonPrimitive(Optional.ofNullable(obj.get("maxMemory")).map(JsonElement::getAsJsonPrimitive).orElse(null), SUGGESTED_MEMORY);
if (maxMemoryN <= 0) maxMemoryN = OperatingSystem.SUGGESTED_MEMORY; if (maxMemoryN <= 0) maxMemoryN = SUGGESTED_MEMORY;
VersionSetting vs = new VersionSetting(); VersionSetting vs = new VersionSetting();

View File

@@ -41,16 +41,10 @@ import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.*;
import org.jackhuang.hmcl.util.Log4jLevel;
import org.jackhuang.hmcl.util.logging.Logger; import org.jackhuang.hmcl.util.logging.Logger;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.*;
import org.jackhuang.hmcl.util.platform.CommandBuilder;
import org.jackhuang.hmcl.util.platform.ManagedProcess;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@@ -65,6 +59,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -98,7 +93,7 @@ public class GameCrashWindow extends Stage {
memory = Optional.ofNullable(launchOptions.getMaxMemory()).map(i -> i + " MB").orElse("-"); memory = Optional.ofNullable(launchOptions.getMaxMemory()).map(i -> i + " MB").orElse("-");
total_memory = OperatingSystem.TOTAL_MEMORY + " MB"; total_memory = MEGABYTES.formatBytes(SystemInfo.getTotalMemorySize());
this.java = launchOptions.getJava().getArchitecture() == Architecture.SYSTEM_ARCH this.java = launchOptions.getJava().getArchitecture() == Architecture.SYSTEM_ARCH
? launchOptions.getJava().getVersion() ? launchOptions.getJava().getVersion()

View File

@@ -98,17 +98,15 @@ public class TaskExecutorDialogPane extends BorderPane {
double speed = speedEvent.getSpeed(); double speed = speedEvent.getSpeed();
if (speed > 1024) { if (speed > 1024) {
speed /= 1024; speed /= 1024;
unit = "KB/s"; unit = "KiB/s";
} }
if (speed > 1024) { if (speed > 1024) {
speed /= 1024; speed /= 1024;
unit = "MB/s"; unit = "MiB/s";
} }
double finalSpeed = speed; double finalSpeed = speed;
String finalUnit = unit; String finalUnit = unit;
Platform.runLater(() -> { Platform.runLater(() -> lblProgress.setText(String.format("%.1f %s", finalSpeed, finalUnit)));
lblProgress.setText(String.format("%.1f %s", finalSpeed, finalUnit));
});
}; };
FileDownloadTask.speedEvent.channel(FileDownloadTask.SpeedEvent.class).registerWeak(speedEventHandler); FileDownloadTask.speedEvent.channel(FileDownloadTask.SpeedEvent.class).registerWeak(speedEventHandler);

View File

@@ -43,7 +43,7 @@ import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage; import org.jackhuang.hmcl.ui.wizard.WizardPage;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.JarUtils; import org.jackhuang.hmcl.util.io.JarUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.SystemInfo;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
@@ -54,6 +54,7 @@ import static org.jackhuang.hmcl.ui.FXUtils.jfxListCellFactory;
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter; import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE; import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE;
import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_SERVER; import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_SERVER;
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -287,12 +288,12 @@ public final class ModpackInfoPage extends Control implements WizardPage {
AtomicBoolean changedByTextField = new AtomicBoolean(false); AtomicBoolean changedByTextField = new AtomicBoolean(false);
FXUtils.onChangeAndOperate(skinnable.minMemory, minMemory -> { FXUtils.onChangeAndOperate(skinnable.minMemory, minMemory -> {
changedByTextField.set(true); changedByTextField.set(true);
slider.setValue(minMemory.intValue() * 1.0 / OperatingSystem.TOTAL_MEMORY); slider.setValue(minMemory.intValue() * 1.0 / MEGABYTES.convertFromBytes(SystemInfo.getTotalMemorySize()));
changedByTextField.set(false); changedByTextField.set(false);
}); });
slider.valueProperty().addListener((value, oldVal, newVal) -> { slider.valueProperty().addListener((value, oldVal, newVal) -> {
if (changedByTextField.get()) return; if (changedByTextField.get()) return;
skinnable.minMemory.set((int) (value.getValue().doubleValue() * OperatingSystem.TOTAL_MEMORY)); skinnable.minMemory.set((int) (value.getValue().doubleValue() * MEGABYTES.convertFromBytes(SystemInfo.getTotalMemorySize())));
}); });
JFXTextField txtMinMemory = new JFXTextField(); JFXTextField txtMinMemory = new JFXTextField();
@@ -301,7 +302,7 @@ public final class ModpackInfoPage extends Control implements WizardPage {
FXUtils.setLimitWidth(txtMinMemory, 60); FXUtils.setLimitWidth(txtMinMemory, 60);
validatingFields.add(txtMinMemory); validatingFields.add(txtMinMemory);
lowerBoundPane.getChildren().setAll(label, slider, txtMinMemory, new Label("MB")); lowerBoundPane.getChildren().setAll(label, slider, txtMinMemory, new Label("MiB"));
} }
pane.getChildren().setAll(title, lowerBoundPane); pane.getChildren().setAll(title, lowerBoundPane);

View File

@@ -51,6 +51,8 @@ import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.java.JavaRuntime; import org.jackhuang.hmcl.java.JavaRuntime;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.SystemInfo;
import org.jackhuang.hmcl.util.platform.hardware.PhysicalMemoryStatus;
import org.jackhuang.hmcl.util.versioning.GameVersionNumber; import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import java.nio.file.Paths; import java.nio.file.Paths;
@@ -58,13 +60,15 @@ import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter; import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
import static org.jackhuang.hmcl.util.DataSizeUnit.GIGABYTES;
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
import static org.jackhuang.hmcl.util.Lang.getTimer; import static org.jackhuang.hmcl.util.Lang.getTimer;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class VersionSettingsPage extends StackPane implements DecoratorPage, VersionPage.VersionLoadable, PageAware { public final class VersionSettingsPage extends StackPane implements DecoratorPage, VersionPage.VersionLoadable, PageAware {
private static final ObjectProperty<OperatingSystem.PhysicalMemoryStatus> memoryStatus = new SimpleObjectProperty<>(OperatingSystem.PhysicalMemoryStatus.INVALID); private static final ObjectProperty<PhysicalMemoryStatus> memoryStatus = new SimpleObjectProperty<>(PhysicalMemoryStatus.INVALID);
private static TimerTask memoryStatusUpdateTask; private static TimerTask memoryStatusUpdateTask;
private static void initMemoryStatusUpdateTask() { private static void initMemoryStatusUpdateTask() {
@@ -74,7 +78,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
memoryStatusUpdateTask = new TimerTask() { memoryStatusUpdateTask = new TimerTask() {
@Override @Override
public void run() { public void run() {
Platform.runLater(() -> memoryStatus.set(OperatingSystem.getPhysicalMemoryStatus())); Platform.runLater(() -> memoryStatus.set(SystemInfo.getPhysicalMemoryStatus()));
} }
}; };
getTimer().scheduleAtFixedRate(memoryStatusUpdateTask, 0, 1000); getTimer().scheduleAtFixedRate(memoryStatusUpdateTask, 0, 1000);
@@ -295,12 +299,12 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
AtomicBoolean changedByTextField = new AtomicBoolean(false); AtomicBoolean changedByTextField = new AtomicBoolean(false);
FXUtils.onChangeAndOperate(maxMemory, maxMemory -> { FXUtils.onChangeAndOperate(maxMemory, maxMemory -> {
changedByTextField.set(true); changedByTextField.set(true);
slider.setValue(maxMemory.intValue() * 1.0 / OperatingSystem.TOTAL_MEMORY); slider.setValue(maxMemory.intValue() * 1.0 / MEGABYTES.convertFromBytes(SystemInfo.getTotalMemorySize()));
changedByTextField.set(false); changedByTextField.set(false);
}); });
slider.valueProperty().addListener((value, oldVal, newVal) -> { slider.valueProperty().addListener((value, oldVal, newVal) -> {
if (changedByTextField.get()) return; if (changedByTextField.get()) return;
maxMemory.set((int) (value.getValue().doubleValue() * OperatingSystem.TOTAL_MEMORY)); maxMemory.set((int) (value.getValue().doubleValue() * MEGABYTES.convertFromBytes(SystemInfo.getTotalMemorySize())));
}); });
JFXTextField txtMaxMemory = new JFXTextField(); JFXTextField txtMaxMemory = new JFXTextField();
@@ -309,7 +313,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
txtMaxMemory.textProperty().bindBidirectional(maxMemory, SafeStringConverter.fromInteger()); txtMaxMemory.textProperty().bindBidirectional(maxMemory, SafeStringConverter.fromInteger());
txtMaxMemory.setValidators(new NumberValidator(i18n("input.number"), false)); txtMaxMemory.setValidators(new NumberValidator(i18n("input.number"), false));
lowerBoundPane.getChildren().setAll(label, slider, txtMaxMemory, new Label("MB")); lowerBoundPane.getChildren().setAll(label, slider, txtMaxMemory, new Label("MiB"));
} }
StackPane progressBarPane = new StackPane(); StackPane progressBarPane = new StackPane();
@@ -343,9 +347,10 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
Label lblPhysicalMemory = new Label(); Label lblPhysicalMemory = new Label();
lblPhysicalMemory.getStyleClass().add("memory-label"); lblPhysicalMemory.getStyleClass().add("memory-label");
digitalPane.setLeft(lblPhysicalMemory); digitalPane.setLeft(lblPhysicalMemory);
lblPhysicalMemory.textProperty().bind(Bindings.createStringBinding(() -> { lblPhysicalMemory.textProperty().bind(Bindings.createStringBinding(() ->
return i18n("settings.memory.used_per_total", memoryStatus.get().getUsedGB(), memoryStatus.get().getTotalGB()); i18n("settings.memory.used_per_total",
}, memoryStatus)); GIGABYTES.convertFromBytes(memoryStatus.get().getUsed()),
GIGABYTES.convertFromBytes(memoryStatus.get().getTotal())), memoryStatus));
Label lblAllocateMemory = new Label(); Label lblAllocateMemory = new Label();
lblAllocateMemory.textProperty().bind(Bindings.createStringBinding(() -> { lblAllocateMemory.textProperty().bind(Bindings.createStringBinding(() -> {
@@ -353,9 +358,9 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
return i18n(memoryStatus.get().hasAvailable() && maxMemory > memoryStatus.get().getAvailable() return i18n(memoryStatus.get().hasAvailable() && maxMemory > memoryStatus.get().getAvailable()
? (chkAutoAllocate.isSelected() ? "settings.memory.allocate.auto.exceeded" : "settings.memory.allocate.manual.exceeded") ? (chkAutoAllocate.isSelected() ? "settings.memory.allocate.auto.exceeded" : "settings.memory.allocate.manual.exceeded")
: (chkAutoAllocate.isSelected() ? "settings.memory.allocate.auto" : "settings.memory.allocate.manual"), : (chkAutoAllocate.isSelected() ? "settings.memory.allocate.auto" : "settings.memory.allocate.manual"),
OperatingSystem.PhysicalMemoryStatus.toGigaBytes(maxMemory), GIGABYTES.convertFromBytes(maxMemory),
OperatingSystem.PhysicalMemoryStatus.toGigaBytes(HMCLGameRepository.getAllocatedMemory(maxMemory, memoryStatus.get().getAvailable(), chkAutoAllocate.isSelected())), GIGABYTES.convertFromBytes(HMCLGameRepository.getAllocatedMemory(maxMemory, memoryStatus.get().getAvailable(), chkAutoAllocate.isSelected())),
OperatingSystem.PhysicalMemoryStatus.toGigaBytes(memoryStatus.get().getAvailable())); GIGABYTES.convertFromBytes(memoryStatus.get().getAvailable()));
}, memoryStatus, maxMemory, chkAutoAllocate.selectedProperty())); }, memoryStatus, maxMemory, chkAutoAllocate.selectedProperty()));
lblAllocateMemory.getStyleClass().add("memory-label"); lblAllocateMemory.getStyleClass().add("memory-label");
digitalPane.setRight(lblAllocateMemory); digitalPane.setRight(lblAllocateMemory);
@@ -507,7 +512,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
cboProcessPriority.getItems().setAll(ProcessPriority.values()); cboProcessPriority.getItems().setAll(ProcessPriority.values());
cboProcessPriority.setConverter(stringConverter(e -> i18n("settings.advanced.process_priority." + e.name().toLowerCase(Locale.ROOT)))); cboProcessPriority.setConverter(stringConverter(e -> i18n("settings.advanced.process_priority." + e.name().toLowerCase(Locale.ROOT))));
memoryStatus.set(OperatingSystem.getPhysicalMemoryStatus()); memoryStatus.set(SystemInfo.getPhysicalMemoryStatus());
componentList.disableProperty().bind(enableSpecificSettings.not()); componentList.disableProperty().bind(enableSpecificSettings.not());
initMemoryStatusUpdateTask(); initMemoryStatusUpdateTask();

View File

@@ -552,7 +552,7 @@ game.crash.reason.jvm_32bit=The game crashed because the current memory allocati
\n\ \n\
If your OS is 64-bit, please install and use a 64-bit Java version. Otherwise, you may need to reinstall a 64-bit OS or get a moderner computer.\n\ If your OS is 64-bit, please install and use a 64-bit Java version. Otherwise, you may need to reinstall a 64-bit OS or get a moderner computer.\n\
\n\ \n\
Or, you can disable the "Automatically Allocate" option in "Global/Instance-specific Settings → Memory" and set the maximum memory allocation size to 1024 MB or below. Or, you can disable the "Automatically Allocate" option in "Global/Instance-specific Settings → Memory" and set the maximum memory allocation size to 1024 MiB or below.
game.crash.reason.loading_crashed_forge=The game crashed because of the mod "%1$s" (%2$s).\n\ game.crash.reason.loading_crashed_forge=The game crashed because of the mod "%1$s" (%2$s).\n\
\n\ \n\
You can try deleting or updating it. You can try deleting or updating it.
@@ -762,7 +762,7 @@ launch.advice.java9=You cannot launch Minecraft 1.12 or earlier with Java 9 or l
launch.advice.modded_java=Some mods may not be compatible with newer Java versions. It is recommended to use Java %s to launch Minecraft %s. launch.advice.modded_java=Some mods may not be compatible with newer Java versions. It is recommended to use Java %s to launch Minecraft %s.
launch.advice.modlauncher8=The Forge version you are using is not compatible with the current Java version. Please try updating Forge. launch.advice.modlauncher8=The Forge version you are using is not compatible with the current Java version. Please try updating Forge.
launch.advice.newer_java=You are using an older Java version to launch the game. It is recommended to update to Java 8, otherwise some mods may cause the game to crash. launch.advice.newer_java=You are using an older Java version to launch the game. It is recommended to update to Java 8, otherwise some mods may cause the game to crash.
launch.advice.not_enough_space=You have allocated a memory size larger than the actual %d MB of memory installed on your computer. You may experience degraded performance or even be unable to launch the game. launch.advice.not_enough_space=You have allocated a memory size larger than the actual %d MiB of memory installed on your computer. You may experience degraded performance or even be unable to launch the game.
launch.advice.require_newer_java_version=The current game version requires Java %s, but we could not find one. Do you want to download one now? launch.advice.require_newer_java_version=The current game version requires Java %s, but we could not find one. Do you want to download one now?
launch.advice.too_large_memory_for_32bit=You have allocated a memory size larger than the memory limitation of the 32-bit Java installation. You may be unable to launch the game. launch.advice.too_large_memory_for_32bit=You have allocated a memory size larger than the memory limitation of the 32-bit Java installation. You may be unable to launch the game.
launch.advice.vanilla_linux_java_8=Minecraft 1.12.2 or earlier only supports Java 8 for the Linux x86-64 platform because the later versions cannot load 32-bit native libraries like liblwjgl.so\n\nPlease download it from java.com or install OpenJDK 8. launch.advice.vanilla_linux_java_8=Minecraft 1.12.2 or earlier only supports Java 8 for the Linux x86-64 platform because the later versions cannot load 32-bit native libraries like liblwjgl.so\n\nPlease download it from java.com or install OpenJDK 8.
@@ -1177,7 +1177,7 @@ settings.advanced.environment_variables=Environment Variables
settings.advanced.game_dir.default=Default (".minecraft/") settings.advanced.game_dir.default=Default (".minecraft/")
settings.advanced.game_dir.independent=Isolated (".minecraft/versions/<instance name>/", except for assets and libraries) settings.advanced.game_dir.independent=Isolated (".minecraft/versions/<instance name>/", except for assets and libraries)
settings.advanced.java_permanent_generation_space=PermGen Space settings.advanced.java_permanent_generation_space=PermGen Space
settings.advanced.java_permanent_generation_space.prompt=in MB settings.advanced.java_permanent_generation_space.prompt=in MiB
settings.advanced.jvm=Java VM Options settings.advanced.jvm=Java VM Options
settings.advanced.jvm_args=Java VM Arguments settings.advanced.jvm_args=Java VM Arguments
settings.advanced.jvm_args.prompt=\ · If the arguments entered in "Java VM arguments" are the same as the default arguments, it will not be added.\n\ settings.advanced.jvm_args.prompt=\ · If the arguments entered in "Java VM arguments" are the same as the default arguments, it will not be added.\n\
@@ -1287,13 +1287,13 @@ settings.launcher.turn_off_animations=Disable Animation (Applies After Restart)
settings.launcher.version_list_source=Version List settings.launcher.version_list_source=Version List
settings.memory=Memory settings.memory=Memory
settings.memory.allocate.auto=%1$.1f GB Minimum / %2$.1f GB Allocated settings.memory.allocate.auto=%1$.1f GiB Minimum / %2$.1f GiB Allocated
settings.memory.allocate.auto.exceeded=%1$.1f GB Minimum / %2$.1f GB Allocated (%3$.1f GB Available) settings.memory.allocate.auto.exceeded=%1$.1f GiB Minimum / %2$.1f GiB Allocated (%3$.1f GiB Available)
settings.memory.allocate.manual=%1$.1f GB Allocated settings.memory.allocate.manual=%1$.1f GiB Allocated
settings.memory.allocate.manual.exceeded=%1$.1f GB Allocated (%3$.1f GB Available) settings.memory.allocate.manual.exceeded=%1$.1f GiB Allocated (%3$.1f GiB Available)
settings.memory.auto_allocate=Automatically Allocate settings.memory.auto_allocate=Automatically Allocate
settings.memory.lower_bound=Minimum Memory settings.memory.lower_bound=Minimum Memory
settings.memory.used_per_total=%1$.1f GB Used / %2$.1f GB Total settings.memory.used_per_total=%1$.1f GiB Used / %2$.1f GiB Total
settings.physical_memory=Physical Memory Size settings.physical_memory=Physical Memory Size
settings.show_log=Show Logs settings.show_log=Show Logs
settings.tabs.installers=Loaders settings.tabs.installers=Loaders

View File

@@ -500,7 +500,7 @@ game.crash.reason.jvm_32bit=El juego se ha colgado porque la asignación de memo
\n\ \n\
Si su sistema operativo es de 64 bits, instale y utilice una versión de Java de 64 bits. De lo contrario, es posible que tenga que volver a instalar un sistema operativo de 64 bits o adquirir un ordenador más moderno.\n\ Si su sistema operativo es de 64 bits, instale y utilice una versión de Java de 64 bits. De lo contrario, es posible que tenga que volver a instalar un sistema operativo de 64 bits o adquirir un ordenador más moderno.\n\
\n\ \n\
O bien, puede desactivar la opción «Asignar automáticamente» en «Config. Global/Específica de instancia → Memoria» y establecer el tamaño máximo de asignación de memoria en 1024 MB o menos. O bien, puede desactivar la opción «Asignar automáticamente» en «Config. Global/Específica de instancia → Memoria» y establecer el tamaño máximo de asignación de memoria en 1024 MiB o menos.
game.crash.reason.loading_crashed_forge=El juego se ha colgado debido al mod «%1$s» (%2$s).\n\ game.crash.reason.loading_crashed_forge=El juego se ha colgado debido al mod «%1$s» (%2$s).\n\
\n\ \n\
Puedes intentar borrarlo o actualizarlo. Puedes intentar borrarlo o actualizarlo.
@@ -767,7 +767,7 @@ launch.advice.java9=No puedes ejecutar Minecraft 1.12 o anterior con Java 9 o m
launch.advice.modded_java=Algunos mods pueden no ser compatibles con las nuevas versiones de Java. Se recomienda utilizar Java %s para iniciar Minecraft %s. launch.advice.modded_java=Algunos mods pueden no ser compatibles con las nuevas versiones de Java. Se recomienda utilizar Java %s para iniciar Minecraft %s.
launch.advice.modlauncher8=La versión de Forge que estás utilizando no es compatible con la versión actual de Java. Por favor, intenta actualizar Forge. launch.advice.modlauncher8=La versión de Forge que estás utilizando no es compatible con la versión actual de Java. Por favor, intenta actualizar Forge.
launch.advice.newer_java=Estás utilizando una versión antigua de Java para iniciar el juego. Se recomienda actualizar a Java 8, de lo contrario algunos mods pueden hacer que el juego se bloquee. launch.advice.newer_java=Estás utilizando una versión antigua de Java para iniciar el juego. Se recomienda actualizar a Java 8, de lo contrario algunos mods pueden hacer que el juego se bloquee.
launch.advice.not_enough_space=Has asignado un tamaño de memoria mayor que los %d MB reales de memoria instalados en tu máquina. Es posible que el rendimiento del juego se vea afectado, o incluso que no puedas iniciar el juego. launch.advice.not_enough_space=Has asignado un tamaño de memoria mayor que los %d MiB reales de memoria instalados en tu máquina. Es posible que el rendimiento del juego se vea afectado, o incluso que no puedas iniciar el juego.
launch.advice.require_newer_java_version=La versión actual del juego requiere Java %s, pero no hemos podido encontrar uno. ¿Quieres descargar uno ahora? launch.advice.require_newer_java_version=La versión actual del juego requiere Java %s, pero no hemos podido encontrar uno. ¿Quieres descargar uno ahora?
launch.advice.too_large_memory_for_32bit=Has asignado un tamaño de memoria mayor que la limitación de memoria de la instalación de Java de 32 bits. Es posible que no puedas iniciar el juego. launch.advice.too_large_memory_for_32bit=Has asignado un tamaño de memoria mayor que la limitación de memoria de la instalación de Java de 32 bits. Es posible que no puedas iniciar el juego.
launch.advice.vanilla_linux_java_8=Minecraft 1.12.2 o inferior sólo admite Java 8 para la plataforma Linux x86-64, porque las versiones posteriores no pueden cargar las bibliotecas nativas de 32 bits como liblwjgl.so\n\nPor favor, descárguelo de java.com, o instale OpenJDK 8. launch.advice.vanilla_linux_java_8=Minecraft 1.12.2 o inferior sólo admite Java 8 para la plataforma Linux x86-64, porque las versiones posteriores no pueden cargar las bibliotecas nativas de 32 bits como liblwjgl.so\n\nPor favor, descárguelo de java.com, o instale OpenJDK 8.
@@ -1182,7 +1182,7 @@ settings.advanced.environment_variables=Variables de entorno
settings.advanced.game_dir.default=Por defecto («.minecraft/») settings.advanced.game_dir.default=Por defecto («.minecraft/»)
settings.advanced.game_dir.independent=Aislar («.minecraft/versions/<nombre de la instancia>/», excepto para los activos y las bibliotecas) settings.advanced.game_dir.independent=Aislar («.minecraft/versions/<nombre de la instancia>/», excepto para los activos y las bibliotecas)
settings.advanced.java_permanent_generation_space=Espacio PermGen settings.advanced.java_permanent_generation_space=Espacio PermGen
settings.advanced.java_permanent_generation_space.prompt=en MB settings.advanced.java_permanent_generation_space.prompt=en MiB
settings.advanced.jvm=Opciones de la máquina virtual de Java settings.advanced.jvm=Opciones de la máquina virtual de Java
settings.advanced.jvm_args=Argumentos de la máquina virtual de Java settings.advanced.jvm_args=Argumentos de la máquina virtual de Java
settings.advanced.jvm_args.prompt=\ · Si los argumentos introducidos en «Argumentos de la máquina virtual de Java» son los mismos que los argumentos por defecto, no se añadirán.\n\ settings.advanced.jvm_args.prompt=\ · Si los argumentos introducidos en «Argumentos de la máquina virtual de Java» son los mismos que los argumentos por defecto, no se añadirán.\n\
@@ -1291,13 +1291,13 @@ settings.launcher.turn_off_animations=Desactivar animación (Se aplica después
settings.launcher.version_list_source=Lista de versiones settings.launcher.version_list_source=Lista de versiones
settings.memory=Memoria settings.memory=Memoria
settings.memory.allocate.auto=%1$.1f GB Mínimo / %2$.1f GB Asignado settings.memory.allocate.auto=%1$.1f GiB Mínimo / %2$.1f GiB Asignado
settings.memory.allocate.auto.exceeded=%1$.1f GB Mínimo / %2$.1f GB Asignado (%3$.1f GB Disponible) settings.memory.allocate.auto.exceeded=%1$.1f GiB Mínimo / %2$.1f GiB Asignado (%3$.1f GiB Disponible)
settings.memory.allocate.manual=%1$.1f GB Asignados settings.memory.allocate.manual=%1$.1f GiB Asignados
settings.memory.allocate.manual.exceeded=%1$.1f GB Asignados (%3$.1f GB Disponibles) settings.memory.allocate.manual.exceeded=%1$.1f GiB Asignados (%3$.1f GiB Disponibles)
settings.memory.auto_allocate=Asignar automáticamente settings.memory.auto_allocate=Asignar automáticamente
settings.memory.lower_bound=Memoria mínima settings.memory.lower_bound=Memoria mínima
settings.memory.used_per_total=%1$.1f GB Utilizados / %2$.1f GB Totales settings.memory.used_per_total=%1$.1f GiB Utilizados / %2$.1f GiB Totales
settings.physical_memory=Tamaño de la memoria física settings.physical_memory=Tamaño de la memoria física
settings.show_log=Mostrar registros settings.show_log=Mostrar registros
settings.tabs.installers=Cargadores settings.tabs.installers=Cargadores

View File

@@ -379,7 +379,7 @@ game.crash.reason.macos_failed_to_find_service_port_for_display=現在のゲー
game.crash.reason.illegal_access_error=一部のmodが原因でゲームがクラッシュしました。\n認識している場合%1$s、modを更新または削除して、再試行してください。 game.crash.reason.illegal_access_error=一部のmodが原因でゲームがクラッシュしました。\n認識している場合%1$s、modを更新または削除して、再試行してください。
game.crash.reason.install_mixinbootstrap=MixinBootstrapが見つからないため、現在のゲームを続行できません。\n<a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a>をインストールしてみてください。インストール後にクラッシュする場合は、モジュールのファイル名の前に英語の「! をモジュールのファイル名の前につけてみてください。 game.crash.reason.install_mixinbootstrap=MixinBootstrapが見つからないため、現在のゲームを続行できません。\n<a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a>をインストールしてみてください。インストール後にクラッシュする場合は、モジュールのファイル名の前に英語の「! をモジュールのファイル名の前につけてみてください。
game.crash.reason.jdk_9=Javaのバージョンが高すぎるため、ゲームを実行できません。\nJava 8をダウンロードしてインストールし、ゲーム設定で新しくインストールしたJavaを選択する必要があります。 game.crash.reason.jdk_9=Javaのバージョンが高すぎるため、ゲームを実行できません。\nJava 8をダウンロードしてインストールし、ゲーム設定で新しくインストールしたJavaを選択する必要があります。
game.crash.reason.jvm_32bit=メモリ割り当てが32ビットJavaVMの制限を超えたため、ゲームがクラッシュしました。\nOSが64ビットの場合は、64ビットJavaをインストールして使用してください。OSが32ビットの場合は、64ビットOSを再インストールするか、新しいコンピュータを変更できます。\nまたは、自動メモリ割り当てを無効にして、最大メモリサイズを1024MB以下に設定できます。 game.crash.reason.jvm_32bit=メモリ割り当てが32ビットJavaVMの制限を超えたため、ゲームがクラッシュしました。\nOSが64ビットの場合は、64ビットJavaをインストールして使用してください。OSが32ビットの場合は、64ビットOSを再インストールするか、新しいコンピュータを変更できます。\nまたは、自動メモリ割り当てを無効にして、最大メモリサイズを1024MiB以下に設定できます。
game.crash.reason.loading_crashed_forge=mod %1$s%2$sがクラッシュしたため、ゲームがクラッシュしました。\n削除または更新を試みることができます。 game.crash.reason.loading_crashed_forge=mod %1$s%2$sがクラッシュしたため、ゲームがクラッシュしました。\n削除または更新を試みることができます。
game.crash.reason.loading_crashed_fabric=mod %1$s がクラッシュしたため、ゲームがクラッシュしました。\n削除または更新を試みることができます。 game.crash.reason.loading_crashed_fabric=mod %1$s がクラッシュしたため、ゲームがクラッシュしました。\n削除または更新を試みることができます。
game.crash.reason.memory_exceeded=JVMが割り当てるのに十分なメモリがないため、ゲームがクラッシュしました。\nこの問題は、ページサイズが小さすぎることが原因です。\nゲーム設定で自動メモリ割り当てをオフにし、メモリ割り当てを次のように調整する必要があります。システムが処理できる値。\nシステムのページサイズを十分な大きさに調整することもできます。 game.crash.reason.memory_exceeded=JVMが割り当てるのに十分なメモリがないため、ゲームがクラッシュしました。\nこの問題は、ページサイズが小さすぎることが原因です。\nゲーム設定で自動メモリ割り当てをオフにし、メモリ割り当てを次のように調整する必要があります。システムが処理できる値。\nシステムのページサイズを十分な大きさに調整することもできます。
@@ -506,8 +506,8 @@ launch.advice.java8_1_13=Minecraft 1.13以降は、Java8以降でのみ実行で
launch.advice.java8_51_1_13=Minecraft 1.13は、1.8.0_51より前のJava8でクラッシュする可能性があります。最新バージョンのJava8をインストールしてください。 launch.advice.java8_51_1_13=Minecraft 1.13は、1.8.0_51より前のJava8でクラッシュする可能性があります。最新バージョンのJava8をインストールしてください。
launch.advice.java9=Java9以降のバージョンのJavaでMinecraft1.12以前を起動することはできません。ゲームを高速化するには、Java8をお勧めします。 launch.advice.java9=Java9以降のバージョンのJavaでMinecraft1.12以前を起動することはできません。ゲームを高速化するには、Java8をお勧めします。
launch.advice.newer_java=多くのMinecraft1.12以降、およびほとんどのModには、Java8が必要です。 launch.advice.newer_java=多くのMinecraft1.12以降、およびほとんどのModには、Java8が必要です。
launch.advice.not_enough_space=割り当てたメモリが多すぎます。物理メモリサイズが%dMBであるため、ゲームがクラッシュする可能性があります。 launch.advice.not_enough_space=割り当てたメモリが多すぎます。物理メモリサイズが%dMiBであるため、ゲームがクラッシュする可能性があります。
launch.advice.too_large_memory_for_32bit=32ビットJavaランタイム環境が原因で、割り当てたメモリが多すぎるため、ゲームがクラッシュする可能性があります。32ビットシステムの最大メモリ容量は1024MBです。 launch.advice.too_large_memory_for_32bit=32ビットJavaランタイム環境が原因で、割り当てたメモリが多すぎるため、ゲームがクラッシュする可能性があります。32ビットシステムの最大メモリ容量は1024MiBです。
launch.advice.vanilla_linux_java_8=Linux x86-64の場合、Minecraft1.12.2以下はJava8でのみ実行できます。\nJava9以降のバージョンでは、liblwjgl.soなどの32ビットネイティブライブラリをロードできません。 launch.advice.vanilla_linux_java_8=Linux x86-64の場合、Minecraft1.12.2以下はJava8でのみ実行できます。\nJava9以降のバージョンでは、liblwjgl.soなどの32ビットネイティブライブラリをロードできません。
launch.advice.vanilla_x86.translation=Minecraftは現在、x86およびx86-64以外のアーキテクチャの公式サポートを提供していません。\nJava for x86-64を使用して、トランスレータを介してminecraftを実行するか、プラットフォームの対応するネイティブライブラリをダウンロードして指定してくださいその配置パス。 launch.advice.vanilla_x86.translation=Minecraftは現在、x86およびx86-64以外のアーキテクチャの公式サポートを提供していません。\nJava for x86-64を使用して、トランスレータを介してminecraftを実行するか、プラットフォームの対応するネイティブライブラリをダウンロードして指定してくださいその配置パス。
launch.failed=起動できません launch.failed=起動できません
@@ -772,8 +772,8 @@ settings.advanced.dont_check_game_completeness=ゲームファイルをスキャ
settings.advanced.dont_check_jvm_validity=JVMがゲームを起動できるかどうかを確認しないでください settings.advanced.dont_check_jvm_validity=JVMがゲームを起動できるかどうかを確認しないでください
settings.advanced.game_dir.default=標準(.minecraft / settings.advanced.game_dir.default=標準(.minecraft /
settings.advanced.game_dir.independent=バージョン独立(.minecraft / versions / <バージョン名> /、アセットとライブラリを除く) settings.advanced.game_dir.independent=バージョン独立(.minecraft / versions / <バージョン名> /、アセットとライブラリを除く)
settings.advanced.java_permanent_generation_space=PermGen Space / MB settings.advanced.java_permanent_generation_space=PermGen Space / MiB
settings.advanced.java_permanent_generation_space.prompt=Java 8以降のメタスペース、MB settings.advanced.java_permanent_generation_space.prompt=Java 8以降のメタスペース、MiB
settings.advanced.jvm=Java仮想マシンの設定 settings.advanced.jvm=Java仮想マシンの設定
settings.advanced.jvm_args=JavaVM引数 settings.advanced.jvm_args=JavaVM引数
settings.advanced.jvm_args.prompt=- 入力パラメータがデフォルトパラメータと同じである場合、追加されません\n\ settings.advanced.jvm_args.prompt=- 入力パラメータがデフォルトパラメータと同じである場合、追加されません\n\

View File

@@ -435,7 +435,7 @@ game.crash.reason.macos_failed_to_find_service_port_for_display=目前遊戲由
game.crash.reason.illegal_access_error=目前遊戲由於某些模組的問題,無法繼續執行。\n如果你認識「%1$s」你可以更新或刪除對應模組再試。 game.crash.reason.illegal_access_error=目前遊戲由於某些模組的問題,無法繼續執行。\n如果你認識「%1$s」你可以更新或刪除對應模組再試。
game.crash.reason.install_mixinbootstrap=目前遊戲由於缺失 MixinBootstrap無法繼續執行。\n你可以嘗試安裝 <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> 解決該問題。若安裝後崩潰,嘗試在該模組的檔案名前加入半形驚嘆號 (!) 嘗試解決。 game.crash.reason.install_mixinbootstrap=目前遊戲由於缺失 MixinBootstrap無法繼續執行。\n你可以嘗試安裝 <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> 解決該問題。若安裝後崩潰,嘗試在該模組的檔案名前加入半形驚嘆號 (!) 嘗試解決。
game.crash.reason.jdk_9=目前遊戲由於 Java 版本過高,無法繼續執行。\n你需要下載安裝 Java 8並在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中將 Java 設定為 1.8 的版本。 game.crash.reason.jdk_9=目前遊戲由於 Java 版本過高,無法繼續執行。\n你需要下載安裝 Java 8並在「(全域/實例特定) 遊戲設定 → 遊戲 Java」中將 Java 設定為 1.8 的版本。
game.crash.reason.jvm_32bit=目前遊戲由於記憶體分配過大,超過了 32 位 Java 記憶體限制,無法繼續執行。\n如果你的電腦是 64 位系統,請下載安裝並更換 64 位 Java。\n如果你的電腦是 32 位系統,你或許可以重新安裝 64 位系統,或換一台新電腦。\n或者你可以關閉「(全域/實例特定) 遊戲設定 → 遊戲記憶體」中的「自動分配」,並且把記憶體限制調節為 1024 MB 或以下。 game.crash.reason.jvm_32bit=目前遊戲由於記憶體分配過大,超過了 32 位 Java 記憶體限制,無法繼續執行。\n如果你的電腦是 64 位系統,請下載安裝並更換 64 位 Java。\n如果你的電腦是 32 位系統,你或許可以重新安裝 64 位系統,或換一台新電腦。\n或者你可以關閉「(全域/實例特定) 遊戲設定 → 遊戲記憶體」中的「自動分配」,並且把記憶體限制調節為 1024 MiB 或以下。
game.crash.reason.loading_crashed_forge=目前遊戲由於模組「%1$s (%2$s)」錯誤,無法繼續執行。\n你可以嘗試刪除或更新該模組以解決問題。 game.crash.reason.loading_crashed_forge=目前遊戲由於模組「%1$s (%2$s)」錯誤,無法繼續執行。\n你可以嘗試刪除或更新該模組以解決問題。
game.crash.reason.loading_crashed_fabric=目前遊戲由於模組「%1$s」錯誤無法繼續執行。\n你可以嘗試刪除或更新該模組以解決問題。 game.crash.reason.loading_crashed_fabric=目前遊戲由於模組「%1$s」錯誤無法繼續執行。\n你可以嘗試刪除或更新該模組以解決問題。
game.crash.reason.mac_jdk_8u261=目前遊戲由於你所使用的 Forge 或 OptiFine 與 Java 衝突而崩潰。\n請嘗試更新 Forge 和 OptiFine或使用 Java 8u251 及更早版本啟動。 game.crash.reason.mac_jdk_8u261=目前遊戲由於你所使用的 Forge 或 OptiFine 與 Java 衝突而崩潰。\n請嘗試更新 Forge 和 OptiFine或使用 Java 8u251 及更早版本啟動。
@@ -578,9 +578,9 @@ launch.advice.java9=低於 (包含) 1.13 的有安裝模組的 Minecraft 版本
launch.advice.modded_java=部分模組可能與高版本 Java 不相容,建議使用 Java %s 啟動 Minecraft %s。 launch.advice.modded_java=部分模組可能與高版本 Java 不相容,建議使用 Java %s 啟動 Minecraft %s。
launch.advice.modlauncher8=你所使用的 Forge 版本與目前使用的 Java 不相容。請更新 Forge。 launch.advice.modlauncher8=你所使用的 Forge 版本與目前使用的 Java 不相容。請更新 Forge。
launch.advice.newer_java=偵測到你正在使用舊版本 Java 啟動遊戲,這可能導致部分模組引發遊戲崩潰,建議更新至 Java 8 後再次啟動。 launch.advice.newer_java=偵測到你正在使用舊版本 Java 啟動遊戲,這可能導致部分模組引發遊戲崩潰,建議更新至 Java 8 後再次啟動。
launch.advice.not_enough_space=你設定的記憶體大小過大,由於超過了系統記憶體大小 %d MB所以可能影響遊戲體驗或無法啟動遊戲。 launch.advice.not_enough_space=你設定的記憶體大小過大,由於超過了系統記憶體大小 %d MiB所以可能影響遊戲體驗或無法啟動遊戲。
launch.advice.require_newer_java_version=目前遊戲版本需要 Java %s但 HMCL 未能找到該 Java 版本你可以點擊「是」HMCL 會自動下載他,是否下載? launch.advice.require_newer_java_version=目前遊戲版本需要 Java %s但 HMCL 未能找到該 Java 版本你可以點擊「是」HMCL 會自動下載他,是否下載?
launch.advice.too_large_memory_for_32bit=你設定的記憶體大小過大,由於可能超過了 32 位元 Java 的記憶體分配限制,所以可能無法啟動遊戲,請將記憶體調至低於 1024 MB 的值。 launch.advice.too_large_memory_for_32bit=你設定的記憶體大小過大,由於可能超過了 32 位元 Java 的記憶體分配限制,所以可能無法啟動遊戲,請將記憶體調至低於 1024 MiB 的值。
launch.advice.vanilla_linux_java_8=對於 Linux x86-64 平台Minecraft 1.12.2 及更低版本與 Java 9+ 不相容,請使用 Java 8 啟動遊戲。 launch.advice.vanilla_linux_java_8=對於 Linux x86-64 平台Minecraft 1.12.2 及更低版本與 Java 9+ 不相容,請使用 Java 8 啟動遊戲。
launch.advice.vanilla_x86.translation=Minecraft 尚未為你的平臺提供完善支援,所以可能影響遊戲體驗或無法啟動遊戲。\n你可以在 <a href="https://learn.microsoft.com/java/openjdk/download">這裡</a> 下載 <b>x86-64</b> 架構的 Java 以獲得更完整的體驗。\n是否繼續啟動 launch.advice.vanilla_x86.translation=Minecraft 尚未為你的平臺提供完善支援,所以可能影響遊戲體驗或無法啟動遊戲。\n你可以在 <a href="https://learn.microsoft.com/java/openjdk/download">這裡</a> 下載 <b>x86-64</b> 架構的 Java 以獲得更完整的體驗。\n是否繼續啟動
launch.advice.unknown=由於以下原因,無法繼續啟動遊戲: launch.advice.unknown=由於以下原因,無法繼續啟動遊戲:
@@ -978,7 +978,7 @@ settings.advanced.environment_variables=環境變數
settings.advanced.game_dir.default=預設 (".minecraft/") settings.advanced.game_dir.default=預設 (".minecraft/")
settings.advanced.game_dir.independent=各實例獨立 (".minecraft/versions/<實例名>/",除 assets、libraries 外) settings.advanced.game_dir.independent=各實例獨立 (".minecraft/versions/<實例名>/",除 assets、libraries 外)
settings.advanced.java_permanent_generation_space=記憶體永久儲存區域 settings.advanced.java_permanent_generation_space=記憶體永久儲存區域
settings.advanced.java_permanent_generation_space.prompt=單位 MB settings.advanced.java_permanent_generation_space.prompt=單位 MiB
settings.advanced.jvm=Java 虛擬機設定 settings.advanced.jvm=Java 虛擬機設定
settings.advanced.jvm_args=Java 虛擬機參數 settings.advanced.jvm_args=Java 虛擬機參數
settings.advanced.jvm_args.prompt=\ · 若在「Java 虛擬機參數」中輸入的參數與預設參數相同,則不會加入;\n\ settings.advanced.jvm_args.prompt=\ · 若在「Java 虛擬機參數」中輸入的參數與預設參數相同,則不會加入;\n\
@@ -1083,13 +1083,13 @@ settings.launcher.turn_off_animations=關閉動畫 (重啟後生效)
settings.launcher.version_list_source=版本清單來源 settings.launcher.version_list_source=版本清單來源
settings.memory=遊戲記憶體 settings.memory=遊戲記憶體
settings.memory.allocate.auto=最低分配 %1$.1f GB / 實際分配 %2$.1f GB settings.memory.allocate.auto=最低分配 %1$.1f GiB / 實際分配 %2$.1f GiB
settings.memory.allocate.auto.exceeded=最低分配 %1$.1f GB / 實際分配 %2$.1f GB (%3$.1f GB 可用) settings.memory.allocate.auto.exceeded=最低分配 %1$.1f GiB / 實際分配 %2$.1f GiB (%3$.1f GiB 可用)
settings.memory.allocate.manual=遊戲分配 %1$.1f GB settings.memory.allocate.manual=遊戲分配 %1$.1f GiB
settings.memory.allocate.manual.exceeded=遊戲分配 %1$.1f GB (%3$.1f GB 可用) settings.memory.allocate.manual.exceeded=遊戲分配 %1$.1f GiB (%3$.1f GiB 可用)
settings.memory.auto_allocate=自動分配 settings.memory.auto_allocate=自動分配
settings.memory.lower_bound=最低分配 settings.memory.lower_bound=最低分配
settings.memory.used_per_total=已使用 %1$.1f GB / 總記憶體 %2$.1f GB settings.memory.used_per_total=已使用 %1$.1f GiB / 總記憶體 %2$.1f GiB
settings.physical_memory=實體記憶體大小 settings.physical_memory=實體記憶體大小
settings.show_log=查看日誌 settings.show_log=查看日誌
settings.tabs.installers=自動安裝 settings.tabs.installers=自動安裝

View File

@@ -439,7 +439,7 @@ game.crash.reason.illegal_access_error=当前游戏由于某些模组的问题
game.crash.reason.install_mixinbootstrap=当前游戏由于缺失 MixinBootstrap无法继续运行。\n你可以尝试安装 <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> 解决该问题。若安装后崩溃,尝试在该模组的文件名前加入半角感叹号 (!) 尝试解决。 game.crash.reason.install_mixinbootstrap=当前游戏由于缺失 MixinBootstrap无法继续运行。\n你可以尝试安装 <a href="https://www.curseforge.com/minecraft/mc-mods/mixinbootstrap">MixinBootstrap</a> 解决该问题。若安装后崩溃,尝试在该模组的文件名前加入半角感叹号 (!) 尝试解决。
game.crash.reason.need_jdk11=当前游戏由于 Java 虚拟机版本不合适,无法继续运行。\n你需要下载安装 <a href="https://bell-sw.com/pages/downloads/#downloads">Java 11</a>,并在“(全局/版本特定) 游戏设置 → 游戏 Java”中将 Java 设置为 11 开头的版本。 game.crash.reason.need_jdk11=当前游戏由于 Java 虚拟机版本不合适,无法继续运行。\n你需要下载安装 <a href="https://bell-sw.com/pages/downloads/#downloads">Java 11</a>,并在“(全局/版本特定) 游戏设置 → 游戏 Java”中将 Java 设置为 11 开头的版本。
game.crash.reason.jdk_9=当前游戏由于 Java 版本过高,无法继续运行。\n你需要下载安装 <a href="https://bell-sw.com/pages/downloads/#downloads">Java 8</a>,并在“(全局/版本特定) 游戏设置 → 游戏 Java”中将 Java 设置为 1.8 的版本。 game.crash.reason.jdk_9=当前游戏由于 Java 版本过高,无法继续运行。\n你需要下载安装 <a href="https://bell-sw.com/pages/downloads/#downloads">Java 8</a>,并在“(全局/版本特定) 游戏设置 → 游戏 Java”中将 Java 设置为 1.8 的版本。
game.crash.reason.jvm_32bit=当前游戏由于内存分配过大,超过了 32 位 Java 内存限制,无法继续运行。\n如果你的电脑是 64 位系统,请下载安装并更换 64 位 Java。<a href="https://bell-sw.com/pages/downloads/#downloads">下载 Java</a>\n如果你的电脑是 32 位系统,你或许可以重新安装 64 位系统,或换一台新电脑。\n或者你可以在“(全局/版本特定) 游戏设置 → 游戏内存”中关闭“自动分配内存”,并且把内存限制调节为 1024 MB 或以下。 game.crash.reason.jvm_32bit=当前游戏由于内存分配过大,超过了 32 位 Java 内存限制,无法继续运行。\n如果你的电脑是 64 位系统,请下载安装并更换 64 位 Java。<a href="https://bell-sw.com/pages/downloads/#downloads">下载 Java</a>\n如果你的电脑是 32 位系统,你或许可以重新安装 64 位系统,或换一台新电脑。\n或者你可以在“(全局/版本特定) 游戏设置 → 游戏内存”中关闭“自动分配内存”,并且把内存限制调节为 1024 MiB 或以下。
game.crash.reason.loading_crashed_forge=当前游戏由于模组“%1$s (%2$s)”错误,无法继续运行。\n你可以尝试删除或更新该模组以解决问题。 game.crash.reason.loading_crashed_forge=当前游戏由于模组“%1$s (%2$s)”错误,无法继续运行。\n你可以尝试删除或更新该模组以解决问题。
game.crash.reason.loading_crashed_fabric=当前游戏由于模组“%1$s”错误无法继续运行。\n你可以尝试删除或更新该模组以解决问题。 game.crash.reason.loading_crashed_fabric=当前游戏由于模组“%1$s”错误无法继续运行。\n你可以尝试删除或更新该模组以解决问题。
game.crash.reason.memory_exceeded=当前游戏由于分配的内存过大,无法继续运行。\n该问题是由于系统页面文件太小导致的。\n你需要在全局特定游戏设置中关闭游戏内存的自动分配并将游戏内存调低至游戏能正常启动为止。\n你还可以尝试将虚拟内存设置调整为“自动管理所有驱动器分页文件大小”<a href="https://docs.hmcl.net/assets/img/hmcl/自动管理所有驱动器分页文件大小.webp">详情</a>。 game.crash.reason.memory_exceeded=当前游戏由于分配的内存过大,无法继续运行。\n该问题是由于系统页面文件太小导致的。\n你需要在全局特定游戏设置中关闭游戏内存的自动分配并将游戏内存调低至游戏能正常启动为止。\n你还可以尝试将虚拟内存设置调整为“自动管理所有驱动器分页文件大小”<a href="https://docs.hmcl.net/assets/img/hmcl/自动管理所有驱动器分页文件大小.webp">详情</a>。
@@ -588,9 +588,9 @@ launch.advice.java9=低于 1.13 的有安装模组的 Minecraft 版本与 Java 9
launch.advice.modded_java=部分模组可能与高版本 Java 不兼容,建议使用 Java %s 启动 Minecraft %s。 launch.advice.modded_java=部分模组可能与高版本 Java 不兼容,建议使用 Java %s 启动 Minecraft %s。
launch.advice.modlauncher8=你所使用的 Forge 版本与当前使用的 Java 不兼容,请更新 Forge。 launch.advice.modlauncher8=你所使用的 Forge 版本与当前使用的 Java 不兼容,请更新 Forge。
launch.advice.newer_java=检测到你正在使用旧版本 Java 启动游戏,这可能导致部分模组引发游戏崩溃,建议更新至 Java 8 后再次启动。 launch.advice.newer_java=检测到你正在使用旧版本 Java 启动游戏,这可能导致部分模组引发游戏崩溃,建议更新至 Java 8 后再次启动。
launch.advice.not_enough_space=你设置的内存大小过大,超过了系统内存容量 %d MB可能导致游戏无法启动。 launch.advice.not_enough_space=你设置的内存大小过大,超过了系统内存容量 %d MiB可能导致游戏无法启动。
launch.advice.require_newer_java_version=当前游戏版本需要 Java %s但 HMCL 未能找到该 Java 版本你可以点击“是”HMCL 会自动下载他,是否下载?\n如遇到问题你可以点击右上角帮助按钮进行求助。 launch.advice.require_newer_java_version=当前游戏版本需要 Java %s但 HMCL 未能找到该 Java 版本你可以点击“是”HMCL 会自动下载他,是否下载?\n如遇到问题你可以点击右上角帮助按钮进行求助。
launch.advice.too_large_memory_for_32bit=你设置的内存大小过大,由于可能超过了 32 位 Java 的内存分配限制,所以可能无法启动游戏,请将内存调至 1024 MB 或更小。\n如遇到问题你可以点击右上角帮助按钮进行求助。 launch.advice.too_large_memory_for_32bit=你设置的内存大小过大,由于可能超过了 32 位 Java 的内存分配限制,所以可能无法启动游戏,请将内存调至 1024 MiB 或更小。\n如遇到问题你可以点击右上角帮助按钮进行求助。
launch.advice.vanilla_linux_java_8=对于 Linux x86-64 平台Minecraft 1.12.2 及更低版本与 Java 9+ 不兼容,请使用 Java 8 启动游戏。\n如遇到问题你可以点击右上角帮助按钮进行求助。 launch.advice.vanilla_linux_java_8=对于 Linux x86-64 平台Minecraft 1.12.2 及更低版本与 Java 9+ 不兼容,请使用 Java 8 启动游戏。\n如遇到问题你可以点击右上角帮助按钮进行求助。
launch.advice.vanilla_x86.translation=Minecraft 尚未为你的平台提供完善支持,所以可能影响游戏体验或无法启动游戏。\n你可以在 <a href="https://learn.microsoft.com/java/openjdk/download">这里</a> 下载 <b>x86-64</b> 架构的 Java 以获得更完整的体验。 launch.advice.vanilla_x86.translation=Minecraft 尚未为你的平台提供完善支持,所以可能影响游戏体验或无法启动游戏。\n你可以在 <a href="https://learn.microsoft.com/java/openjdk/download">这里</a> 下载 <b>x86-64</b> 架构的 Java 以获得更完整的体验。
launch.advice.unknown=由于以下原因,无法继续启动游戏: launch.advice.unknown=由于以下原因,无法继续启动游戏:
@@ -988,7 +988,7 @@ settings.advanced.environment_variables=环境变量
settings.advanced.game_dir.default=默认 (".minecraft/") settings.advanced.game_dir.default=默认 (".minecraft/")
settings.advanced.game_dir.independent=各版本独立 (存放在 ".minecraft/versions/<版本名>/",除 assets、libraries 外) settings.advanced.game_dir.independent=各版本独立 (存放在 ".minecraft/versions/<版本名>/",除 assets、libraries 外)
settings.advanced.java_permanent_generation_space=内存永久保存区域 settings.advanced.java_permanent_generation_space=内存永久保存区域
settings.advanced.java_permanent_generation_space.prompt=单位 MB settings.advanced.java_permanent_generation_space.prompt=单位 MiB
settings.advanced.jvm=Java 虚拟机设置 settings.advanced.jvm=Java 虚拟机设置
settings.advanced.jvm_args=Java 虚拟机参数 settings.advanced.jvm_args=Java 虚拟机参数
settings.advanced.jvm_args.prompt=\ · 若在“Java 虚拟机参数”输入的参数与默认参数相同,则不会添加;\n\ settings.advanced.jvm_args.prompt=\ · 若在“Java 虚拟机参数”输入的参数与默认参数相同,则不会添加;\n\
@@ -1093,13 +1093,13 @@ settings.launcher.turn_off_animations=关闭动画 (重启后生效)
settings.launcher.version_list_source=版本列表源 settings.launcher.version_list_source=版本列表源
settings.memory=游戏内存 settings.memory=游戏内存
settings.memory.allocate.auto=最低分配 %1$.1f GB / 实际分配 %2$.1f GB settings.memory.allocate.auto=最低分配 %1$.1f GiB / 实际分配 %2$.1f GiB
settings.memory.allocate.auto.exceeded=最低分配 %1$.1f GB / 实际分配 %2$.1f GB (%3$.1f GB 可用) settings.memory.allocate.auto.exceeded=最低分配 %1$.1f GiB / 实际分配 %2$.1f GiB (%3$.1f GiB 可用)
settings.memory.allocate.manual=游戏分配 %1$.1f GB settings.memory.allocate.manual=游戏分配 %1$.1f GiB
settings.memory.allocate.manual.exceeded=游戏分配 %1$.1f GB (设备仅 %3$.1f GB 可用) settings.memory.allocate.manual.exceeded=游戏分配 %1$.1f GiB (设备仅 %3$.1f GiB 可用)
settings.memory.auto_allocate=自动分配内存 settings.memory.auto_allocate=自动分配内存
settings.memory.lower_bound=最低内存分配 settings.memory.lower_bound=最低内存分配
settings.memory.used_per_total=设备中已使用 %1$.1f GB / 设备总内存 %2$.1f GB settings.memory.used_per_total=设备中已使用 %1$.1f GiB / 设备总内存 %2$.1f GiB
settings.physical_memory=物理内存大小 settings.physical_memory=物理内存大小
settings.show_log=查看日志 settings.show_log=查看日志
settings.tabs.installers=自动安装 settings.tabs.installers=自动安装

View File

@@ -212,7 +212,7 @@ public class DefaultLauncher extends Launcher {
if (javaVersion <= 8) { if (javaVersion <= 8) {
res.addUnstableDefault("MaxInlineLevel", "15"); res.addUnstableDefault("MaxInlineLevel", "15");
} }
if (is64bit && OperatingSystem.TOTAL_MEMORY > 4 * 1024) { if (is64bit && SystemInfo.getTotalMemorySize() > 4L * 1024 * 1024 * 1024) {
res.addUnstableDefault("DontCompileHugeMethods", false); res.addUnstableDefault("DontCompileHugeMethods", false);
res.addUnstableDefault("MaxNodeLimit", "240000"); res.addUnstableDefault("MaxNodeLimit", "240000");
res.addUnstableDefault("NodeLimitFudgeFactor", "8000"); res.addUnstableDefault("NodeLimitFudgeFactor", "8000");

View File

@@ -0,0 +1,66 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.util;
import java.text.DecimalFormat;
/**
* @author Glavo
*/
public enum DataSizeUnit {
BYTES,
KILOBYTES,
MEGABYTES,
GIGABYTES,
TERABYTES;
private static final DataSizeUnit[] VALUES = values();
private static final DecimalFormat FORMAT = new DecimalFormat("#.##");
public static String format(long bytes) {
for (int i = VALUES.length - 1; i > 0; i--) {
DataSizeUnit unit = VALUES[i];
if (bytes >= unit.bytes) {
return unit.formatBytes(bytes);
}
}
return bytes == 1 ? "1 byte" : bytes + " bytes";
}
private final long bytes = 1L << (ordinal() * 10);
private final char abbreviationChar = name().charAt(0);
private final String abbreviation = abbreviationChar == 'B' ? "B" : abbreviationChar + "iB";
public double convertFromBytes(long bytes) {
return (double) bytes / this.bytes;
}
public long convertToBytes(double amount) {
return (long) (amount * this.bytes);
}
private String format(double amount) {
return FORMAT.format(amount) + " " + this.abbreviation;
}
public String formatBytes(long bytes) {
return format(convertFromBytes(bytes));
}
}

View File

@@ -85,16 +85,6 @@ public enum OperatingSystem {
*/ */
public static final OperatingSystem CURRENT_OS = parseOSName(System.getProperty("os.name")); public static final OperatingSystem CURRENT_OS = parseOSName(System.getProperty("os.name"));
/**
* The total memory/MB this computer have.
*/
public static final int TOTAL_MEMORY;
/**
* The suggested memory size/MB for Minecraft to allocate.
*/
public static final int SUGGESTED_MEMORY;
public static final String PATH_SEPARATOR = File.pathSeparator; public static final String PATH_SEPARATOR = File.pathSeparator;
public static final String FILE_SEPARATOR = File.separator; public static final String FILE_SEPARATOR = File.separator;
public static final String LINE_SEPARATOR = System.lineSeparator(); public static final String LINE_SEPARATOR = System.lineSeparator();
@@ -129,8 +119,6 @@ public enum OperatingSystem {
private static final String[] INVALID_RESOURCE_BASENAMES; private static final String[] INVALID_RESOURCE_BASENAMES;
private static final String[] INVALID_RESOURCE_FULLNAMES; private static final String[] INVALID_RESOURCE_FULLNAMES;
private static final Pattern MEMINFO_PATTERN = Pattern.compile("^(?<key>.*?):\\s+(?<value>\\d+) kB?$");
static { static {
String nativeEncoding = System.getProperty("native.encoding"); String nativeEncoding = System.getProperty("native.encoding");
String hmclNativeEncoding = System.getProperty("hmcl.native.encoding"); String hmclNativeEncoding = System.getProperty("hmcl.native.encoding");
@@ -246,13 +234,6 @@ public enum OperatingSystem {
OS_RELEASE_NAME = osRelease.get("NAME"); OS_RELEASE_NAME = osRelease.get("NAME");
OS_RELEASE_PRETTY_NAME = osRelease.get("PRETTY_NAME"); OS_RELEASE_PRETTY_NAME = osRelease.get("PRETTY_NAME");
PhysicalMemoryStatus physicalMemoryStatus = getPhysicalMemoryStatus();
TOTAL_MEMORY = physicalMemoryStatus != PhysicalMemoryStatus.INVALID
? (int) (physicalMemoryStatus.getTotal() / 1024 / 1024)
: 1024;
SUGGESTED_MEMORY = TOTAL_MEMORY >= 32768 ? 8192 : (int) (Math.round(1.0 * TOTAL_MEMORY / 4.0 / 128.0) * 128);
// setup the invalid names // setup the invalid names
if (CURRENT_OS == WINDOWS) { if (CURRENT_OS == WINDOWS) {
// valid names and characters taken from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp // valid names and characters taken from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp
@@ -315,48 +296,6 @@ public enum OperatingSystem {
return major >= 6 && !SYSTEM_VERSION.startsWith("6.0"); return major >= 6 && !SYSTEM_VERSION.startsWith("6.0");
} }
@SuppressWarnings("deprecation")
public static PhysicalMemoryStatus getPhysicalMemoryStatus() {
if (CURRENT_OS == LINUX) {
try {
long free = 0, available = 0, total = 0;
for (String line : Files.readAllLines(Paths.get("/proc/meminfo"))) {
Matcher matcher = MEMINFO_PATTERN.matcher(line);
if (matcher.find()) {
String key = matcher.group("key");
String value = matcher.group("value");
if ("MemAvailable".equals(key)) {
available = Long.parseLong(value) * 1024;
}
if ("MemFree".equals(key)) {
free = Long.parseLong(value) * 1024;
}
if ("MemTotal".equals(key)) {
total = Long.parseLong(value) * 1024;
}
}
}
if (total > 0) {
return new PhysicalMemoryStatus(total, available > 0 ? available : free);
}
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
try {
java.lang.management.OperatingSystemMXBean bean = java.lang.management.ManagementFactory.getOperatingSystemMXBean();
if (bean instanceof com.sun.management.OperatingSystemMXBean) {
com.sun.management.OperatingSystemMXBean sunBean =
(com.sun.management.OperatingSystemMXBean)
java.lang.management.ManagementFactory.getOperatingSystemMXBean();
return new PhysicalMemoryStatus(sunBean.getTotalPhysicalMemorySize(), sunBean.getFreePhysicalMemorySize());
}
} catch (NoClassDefFoundError ignored) {
}
return PhysicalMemoryStatus.INVALID;
}
@SuppressWarnings("removal") @SuppressWarnings("removal")
public static void forceGC() { public static void forceGC() {
System.gc(); System.gc();
@@ -420,48 +359,4 @@ public enum OperatingSystem {
return true; return true;
} }
public static class PhysicalMemoryStatus {
private final long total;
private final long available;
public PhysicalMemoryStatus(long total, long available) {
this.total = total;
this.available = available;
}
public long getTotal() {
return total;
}
public double getTotalGB() {
return toGigaBytes(total);
}
public long getUsed() {
return hasAvailable() ? total - available : 0;
}
public double getUsedGB() {
return toGigaBytes(getUsed());
}
public long getAvailable() {
return available;
}
public double getAvailableGB() {
return toGigaBytes(available);
}
public boolean hasAvailable() {
return available >= 0;
}
public static double toGigaBytes(long bytes) {
return bytes / 1024. / 1024. / 1024.;
}
public static final PhysicalMemoryStatus INVALID = new PhysicalMemoryStatus(0, -1);
}
} }

View File

@@ -17,8 +17,10 @@
*/ */
package org.jackhuang.hmcl.util.platform; package org.jackhuang.hmcl.util.platform;
import org.jackhuang.hmcl.util.DataSizeUnit;
import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard;
import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector; import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector;
import org.jackhuang.hmcl.util.platform.hardware.PhysicalMemoryStatus;
import org.jackhuang.hmcl.util.platform.linux.LinuxHardwareDetector; import org.jackhuang.hmcl.util.platform.linux.LinuxHardwareDetector;
import org.jackhuang.hmcl.util.platform.macos.MacOSHardwareDetector; import org.jackhuang.hmcl.util.platform.macos.MacOSHardwareDetector;
import org.jackhuang.hmcl.util.platform.windows.WindowsHardwareDetector; import org.jackhuang.hmcl.util.platform.windows.WindowsHardwareDetector;
@@ -44,13 +46,15 @@ public final class SystemInfo {
DETECTOR = new HardwareDetector(); DETECTOR = new HardwareDetector();
} }
public static final long TOTAL_MEMORY = DETECTOR.getTotalMemorySize();
public static final @Nullable List<GraphicsCard> GRAPHICS_CARDS = DETECTOR.detectGraphicsCards(); public static final @Nullable List<GraphicsCard> GRAPHICS_CARDS = DETECTOR.detectGraphicsCards();
} }
public static void initialize() { public static void initialize() {
StringBuilder builder = new StringBuilder("System Info:"); StringBuilder builder = new StringBuilder("System Info:");
List<GraphicsCard> graphicsCards = getGraphicsCards();
// Graphics Card
List<GraphicsCard> graphicsCards = getGraphicsCards();
if (graphicsCards != null) { if (graphicsCards != null) {
if (graphicsCards.isEmpty()) if (graphicsCards.isEmpty())
builder.append("\n - GPU: Not Found"); builder.append("\n - GPU: Not Found");
@@ -64,18 +68,46 @@ public final class SystemInfo {
} }
} }
OperatingSystem.PhysicalMemoryStatus memoryStatus = OperatingSystem.getPhysicalMemoryStatus(); // Memory
if (memoryStatus.getTotal() > 0 && memoryStatus.getAvailable() > 0) { long totalMemorySize = getTotalMemorySize();
builder.append("\n - Memory: ") long usedMemorySize = getUsedMemorySize();
.append(String.format("%.2f GiB / %.2f GiB (%d%%)",
memoryStatus.getUsedGB(), memoryStatus.getTotalGB(), builder.append("\n - Memory: ")
(int) (((double) memoryStatus.getUsed() / memoryStatus.getTotal()) * 100) .append(DataSizeUnit.format(usedMemorySize))
)); .append(" / ")
} .append(DataSizeUnit.format(totalMemorySize));
if (totalMemorySize > 0 && usedMemorySize > 0)
builder.append(" (").append((int) (((double) usedMemorySize / totalMemorySize) * 100)).append("%)");
LOG.info(builder.toString()); LOG.info(builder.toString());
} }
public static PhysicalMemoryStatus getPhysicalMemoryStatus() {
long totalMemorySize = getTotalMemorySize();
long freeMemorySize = getFreeMemorySize();
return totalMemorySize > 0 && freeMemorySize >= 0
? new PhysicalMemoryStatus(totalMemorySize, freeMemorySize)
: PhysicalMemoryStatus.INVALID;
}
public static long getTotalMemorySize() {
return Holder.TOTAL_MEMORY;
}
public static long getFreeMemorySize() {
return Holder.DETECTOR.getFreeMemorySize();
}
public static long getUsedMemorySize() {
long totalMemorySize = getTotalMemorySize();
if (totalMemorySize <= 0)
return 0;
return Long.max(0, totalMemorySize - getFreeMemorySize());
}
public static @Nullable List<GraphicsCard> getGraphicsCards() { public static @Nullable List<GraphicsCard> getGraphicsCards() {
return Holder.GRAPHICS_CARDS; return Holder.GRAPHICS_CARDS;
} }

View File

@@ -19,13 +19,40 @@ package org.jackhuang.hmcl.util.platform.hardware;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.util.List; import java.util.List;
/** /**
* @author Glavo * @author Glavo
*/ */
@SuppressWarnings("ALL")
public class HardwareDetector { public class HardwareDetector {
public @Nullable List<GraphicsCard> detectGraphicsCards() { public @Nullable List<GraphicsCard> detectGraphicsCards() {
return null; return null;
} }
public long getTotalMemorySize() {
try {
OperatingSystemMXBean bean = ManagementFactory.getOperatingSystemMXBean();
if (bean instanceof com.sun.management.OperatingSystemMXBean) {
return ((com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean()).getTotalPhysicalMemorySize();
}
} catch (NoClassDefFoundError ignored) {
}
return 0L;
}
public long getFreeMemorySize() {
try {
OperatingSystemMXBean bean = ManagementFactory.getOperatingSystemMXBean();
if (bean instanceof com.sun.management.OperatingSystemMXBean) {
return ((com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean()).getFreePhysicalMemorySize();
}
} catch (NoClassDefFoundError ignored) {
}
return 0L;
}
} }

View File

@@ -0,0 +1,46 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.util.platform.hardware;
public final class PhysicalMemoryStatus {
private final long total;
private final long available;
public PhysicalMemoryStatus(long total, long available) {
this.total = total;
this.available = available;
}
public long getTotal() {
return total;
}
public long getUsed() {
return hasAvailable() ? total - available : 0;
}
public long getAvailable() {
return available;
}
public boolean hasAvailable() {
return available >= 0;
}
public static final PhysicalMemoryStatus INVALID = new PhysicalMemoryStatus(0, -1);
}

View File

@@ -21,7 +21,16 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard;
import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector; import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/** /**
* @author Glavo * @author Glavo
@@ -34,4 +43,62 @@ public final class LinuxHardwareDetector extends HardwareDetector {
return null; return null;
return LinuxGPUDetector.detectAll(); return LinuxGPUDetector.detectAll();
} }
private static final Path MEMINFO = Paths.get("/proc/meminfo");
private static final Pattern MEMINFO_PATTERN = Pattern.compile("^.+:\\s*(?<value>\\d+)\\s*kB?$");
private static long parseMemoryInfoLine(final String line) throws IOException {
Matcher matcher = MEMINFO_PATTERN.matcher(line);
if (!matcher.matches())
throw new IOException("Unable to parse line in /proc/meminfo: " + line);
return Long.parseLong(matcher.group("value")) * 1024;
}
@Override
public long getTotalMemorySize() {
try (BufferedReader reader = Files.newBufferedReader(MEMINFO)) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("MemTotal:")) {
long total = parseMemoryInfoLine(line);
if (total <= 0)
throw new IOException("Invalid total memory size: " + line + " kB");
return total;
}
}
} catch (Throwable e) {
LOG.warning("Failed to parse /proc/meminfo", e);
}
return super.getTotalMemorySize();
}
@Override
public long getFreeMemorySize() {
try (BufferedReader reader = Files.newBufferedReader(MEMINFO)) {
long free = -1L;
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("MemAvailable:")) {
long available = parseMemoryInfoLine(line);
if (available < 0)
throw new IOException("Invalid available memory size: " + line + " kB");
return available;
}
if (line.startsWith("MemFree:"))
free = parseMemoryInfoLine(line);
}
if (free >= 0)
return free;
} catch (Throwable e) {
LOG.warning("Failed to parse /proc/meminfo", e);
}
return super.getFreeMemorySize();
}
} }

View File

@@ -48,4 +48,9 @@ public interface Kernel32 extends StdCallLibrary {
* @see <a href="https://learn.microsoft.com/windows/win32/api/winnls/nf-winnls-getusergeoid">GetUserGeoID function</a> * @see <a href="https://learn.microsoft.com/windows/win32/api/winnls/nf-winnls-getusergeoid">GetUserGeoID function</a>
*/ */
int GetUserGeoID(int geoClass); int GetUserGeoID(int geoClass);
/**
* @see <a href="https://learn.microsoft.com/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex">GlobalMemoryStatusEx function</a>
*/
boolean GlobalMemoryStatusEx(WinTypes.MEMORYSTATUSEX lpBuffer);
} }

View File

@@ -60,4 +60,33 @@ public interface WinTypes {
); );
} }
} }
/**
* @see <a href="https://learn.microsoft.com/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex">MEMORYSTATUSEX structure</a>
*/
final class MEMORYSTATUSEX extends Structure {
public int dwLength;
public int dwMemoryLoad;
public long ullTotalPhys;
public long ullAvailPhys;
public long ullTotalPageFile;
public long ullAvailPageFile;
public long ullTotalVirtual;
public long ullAvailVirtual;
public long ullAvailExtendedVirtual;
public MEMORYSTATUSEX() {
dwLength = size();
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(
"dwLength", "dwMemoryLoad",
"ullTotalPhys", "ullAvailPhys", "ullTotalPageFile", "ullAvailPageFile",
"ullTotalVirtual", "ullAvailVirtual", "ullAvailExtendedVirtual");
}
}
;
} }

View File

@@ -21,6 +21,7 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.io.IOUtils;
import org.jackhuang.hmcl.util.platform.NativeUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard;
import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector; import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector;
@@ -133,4 +134,36 @@ public final class WindowsHardwareDetector extends HardwareDetector {
return Collections.emptyList(); return Collections.emptyList();
} }
} }
@Override
public long getTotalMemorySize() {
if (NativeUtils.USE_JNA) {
Kernel32 kernel32 = Kernel32.INSTANCE;
if (kernel32 != null) {
WinTypes.MEMORYSTATUSEX status = new WinTypes.MEMORYSTATUSEX();
if (kernel32.GlobalMemoryStatusEx(status))
return status.ullTotalPhys;
else
LOG.warning("Failed to get memory status: " + kernel32.GetLastError());
}
}
return super.getTotalMemorySize();
}
@Override
public long getFreeMemorySize() {
if (NativeUtils.USE_JNA) {
Kernel32 kernel32 = Kernel32.INSTANCE;
if (kernel32 != null) {
WinTypes.MEMORYSTATUSEX status = new WinTypes.MEMORYSTATUSEX();
if (kernel32.GlobalMemoryStatusEx(status))
return status.ullAvailPhys;
else
LOG.warning("Failed to get memory status: " + kernel32.GetLastError());
}
}
return super.getFreeMemorySize();
}
} }

View File

@@ -0,0 +1,65 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.util;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public final class DataSizeUnitTest {
@Test
public void testToString() {
assertEquals("0 bytes", DataSizeUnit.format(0));
assertEquals("1 byte", DataSizeUnit.format(1));
assertEquals("2 bytes", DataSizeUnit.format(2));
assertEquals("100 bytes", DataSizeUnit.format(100));
assertEquals("1023 bytes", DataSizeUnit.format(1023));
assertEquals("1 KiB", DataSizeUnit.format(1024));
assertEquals("1 KiB", DataSizeUnit.format(1025));
assertEquals("1.07 KiB", DataSizeUnit.format(1100));
assertEquals("4 KiB", DataSizeUnit.format(4096));
assertEquals("1 MiB", DataSizeUnit.format(1024 * 1024));
assertEquals("1.5 MiB", DataSizeUnit.format((long) (1.5 * 1024 * 1024)));
assertEquals("1 GiB", DataSizeUnit.format(1024 * 1024 * 1024));
assertEquals("1.5 GiB", DataSizeUnit.format((long) (1.5 * 1024 * 1024 * 1024)));
assertEquals("1 TiB", DataSizeUnit.format(1024L * 1024 * 1024 * 1024));
assertEquals("1.5 TiB", DataSizeUnit.format((long) (1.5 * 1024 * 1024 * 1024 * 1024)));
}
@Test
public void testConvertFromBytes() {
assertEquals(1, DataSizeUnit.KILOBYTES.convertFromBytes(1024L));
assertEquals(1.5, DataSizeUnit.KILOBYTES.convertFromBytes((long) (1024. * 1.5)));
assertEquals(1, DataSizeUnit.MEGABYTES.convertFromBytes(1024L * 1024));
assertEquals(1.5, DataSizeUnit.MEGABYTES.convertFromBytes((long) (1024 * 1024 * 1.5)));
}
@Test
public void testConvertToBytes() {
assertEquals(10., DataSizeUnit.BYTES.convertToBytes(10));
assertEquals(10. * 1024, DataSizeUnit.KILOBYTES.convertToBytes(10));
assertEquals(10. * 1024 * 1024, DataSizeUnit.MEGABYTES.convertToBytes(10));
assertEquals(10. * 1024 * 1024 * 1024, DataSizeUnit.GIGABYTES.convertToBytes(10));
assertEquals(10. * 1024 * 1024 * 1024 * 1024, DataSizeUnit.TERABYTES.convertToBytes(10));
}
private DataSizeUnitTest() {
}
}