在 SystemInfo 中采集内存信息 (#3903)
This commit is contained in:
@@ -212,7 +212,7 @@ public class DefaultLauncher extends Launcher {
|
||||
if (javaVersion <= 8) {
|
||||
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("MaxNodeLimit", "240000");
|
||||
res.addUnstableDefault("NodeLimitFudgeFactor", "8000");
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -85,16 +85,6 @@ public enum OperatingSystem {
|
||||
*/
|
||||
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 FILE_SEPARATOR = File.separator;
|
||||
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_FULLNAMES;
|
||||
|
||||
private static final Pattern MEMINFO_PATTERN = Pattern.compile("^(?<key>.*?):\\s+(?<value>\\d+) kB?$");
|
||||
|
||||
static {
|
||||
String nativeEncoding = System.getProperty("native.encoding");
|
||||
String hmclNativeEncoding = System.getProperty("hmcl.native.encoding");
|
||||
@@ -246,13 +234,6 @@ public enum OperatingSystem {
|
||||
OS_RELEASE_NAME = osRelease.get("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
|
||||
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
|
||||
@@ -315,48 +296,6 @@ public enum OperatingSystem {
|
||||
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")
|
||||
public static void forceGC() {
|
||||
System.gc();
|
||||
@@ -420,48 +359,4 @@ public enum OperatingSystem {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
*/
|
||||
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.HardwareDetector;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.PhysicalMemoryStatus;
|
||||
import org.jackhuang.hmcl.util.platform.linux.LinuxHardwareDetector;
|
||||
import org.jackhuang.hmcl.util.platform.macos.MacOSHardwareDetector;
|
||||
import org.jackhuang.hmcl.util.platform.windows.WindowsHardwareDetector;
|
||||
@@ -44,13 +46,15 @@ public final class SystemInfo {
|
||||
DETECTOR = new HardwareDetector();
|
||||
}
|
||||
|
||||
public static final long TOTAL_MEMORY = DETECTOR.getTotalMemorySize();
|
||||
public static final @Nullable List<GraphicsCard> GRAPHICS_CARDS = DETECTOR.detectGraphicsCards();
|
||||
}
|
||||
|
||||
public static void initialize() {
|
||||
StringBuilder builder = new StringBuilder("System Info:");
|
||||
List<GraphicsCard> graphicsCards = getGraphicsCards();
|
||||
|
||||
// Graphics Card
|
||||
List<GraphicsCard> graphicsCards = getGraphicsCards();
|
||||
if (graphicsCards != null) {
|
||||
if (graphicsCards.isEmpty())
|
||||
builder.append("\n - GPU: Not Found");
|
||||
@@ -64,18 +68,46 @@ public final class SystemInfo {
|
||||
}
|
||||
}
|
||||
|
||||
OperatingSystem.PhysicalMemoryStatus memoryStatus = OperatingSystem.getPhysicalMemoryStatus();
|
||||
if (memoryStatus.getTotal() > 0 && memoryStatus.getAvailable() > 0) {
|
||||
builder.append("\n - Memory: ")
|
||||
.append(String.format("%.2f GiB / %.2f GiB (%d%%)",
|
||||
memoryStatus.getUsedGB(), memoryStatus.getTotalGB(),
|
||||
(int) (((double) memoryStatus.getUsed() / memoryStatus.getTotal()) * 100)
|
||||
));
|
||||
}
|
||||
// Memory
|
||||
long totalMemorySize = getTotalMemorySize();
|
||||
long usedMemorySize = getUsedMemorySize();
|
||||
|
||||
builder.append("\n - Memory: ")
|
||||
.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());
|
||||
}
|
||||
|
||||
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() {
|
||||
return Holder.GRAPHICS_CARDS;
|
||||
}
|
||||
|
||||
@@ -19,13 +19,40 @@ package org.jackhuang.hmcl.util.platform.hardware;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
public class HardwareDetector {
|
||||
public @Nullable List<GraphicsCard> detectGraphicsCards() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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.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.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
/**
|
||||
* @author Glavo
|
||||
@@ -34,4 +43,62 @@ public final class LinuxHardwareDetector extends HardwareDetector {
|
||||
return null;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
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.hardware.GraphicsCard;
|
||||
import org.jackhuang.hmcl.util.platform.hardware.HardwareDetector;
|
||||
@@ -133,4 +134,36 @@ public final class WindowsHardwareDetector extends HardwareDetector {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user