Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.jackhuang.hmcl.util.logging.Logger.LOG;

Expand Down Expand Up @@ -149,4 +151,63 @@ public List<GraphicsCard> detectGraphicsCards() {

return Collections.emptyList();
}

private static final Pattern PAGE_SIZE_PATTERN = Pattern.compile("\\(page size of (?<size>\\d+) bytes\\)");

@Override
public long getFreeMemorySize() {
vmStat:
try {
Map<String, String> stats = SystemUtils.run(List.of("/usr/bin/vm_stat"),
inputStream -> KeyValuePairUtils.loadPairs(
new BufferedReader(new InputStreamReader(inputStream, OperatingSystem.NATIVE_CHARSET))));
Comment on lines +157 to +163
Comment on lines +160 to +163
String statistics = stats.get("Mach Virtual Memory Statistics");

long pageSize;
long pagesFree;
long pagesInactive;
long pagesSpeculative;

if (statistics != null) {
Matcher matcher = PAGE_SIZE_PATTERN.matcher(statistics);
if (matcher.find()) {
pageSize = Long.parseLong(matcher.group("size"));
} else {
break vmStat;
}
} else {
break vmStat;
}

String pagesFreeStr = stats.get("Pages free");
if (pagesFreeStr != null && pagesFreeStr.endsWith(".")) {
pagesFree = Long.parseUnsignedLong(pagesFreeStr, 0, pagesFreeStr.length() - 1, 10);
} else {
break vmStat;
}

String pagesInactiveStr = stats.get("Pages inactive");
if (pagesInactiveStr != null && pagesInactiveStr.endsWith(".")) {
pagesInactive = Long.parseUnsignedLong(pagesInactiveStr, 0, pagesInactiveStr.length() - 1, 10);
} else {
break vmStat;
}

String pagesSpeculativeStr = stats.get("Pages speculative");
if (pagesSpeculativeStr != null && pagesSpeculativeStr.endsWith(".")) {
pagesSpeculative = Long.parseUnsignedLong(pagesSpeculativeStr, 0, pagesSpeculativeStr.length() - 1, 10);
} else {
break vmStat;
}

long available = (pagesFree + pagesSpeculative + pagesInactive) * pageSize;
if (available > 0) {
return available;
}
} catch (Throwable e) {
LOG.warning("Failed to parse vm_stat output", e);
}

return super.getFreeMemorySize();
}
}
Loading