mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2026-05-18 23:14:40 -04:00
Feat[launcher]: check whether user is running out of addressable memory for Java
This commit is contained in:
@@ -12,6 +12,22 @@ public class Architecture {
|
||||
public static final int ARCH_X86 = 0x4;
|
||||
public static final int ARCH_X86_64 = 0x8;
|
||||
|
||||
/* On both 32-bit ARM and x86, the top 1GB is reserved for kernel use. */
|
||||
public static final long ADDRESS_SPACE_LIMIT_32_BIT = 0xbfffffffL;
|
||||
/*
|
||||
* Technically, this is supposed to be 48 bits on x86_64, but nobody's allocating
|
||||
* 524288 terabytes of RAM on Pojav any time soon.
|
||||
*/
|
||||
public static final long ADDRESS_SPACE_LIMIT_64_BIT = 0x7fffffffffL;
|
||||
|
||||
/**
|
||||
* Get the highest byte accessible within the process's address space.
|
||||
* @return the highest byte accessible within the process's address space.
|
||||
*/
|
||||
public static long getAddressSpaceLimit() {
|
||||
return is64BitsDevice() ? ADDRESS_SPACE_LIMIT_64_BIT : ADDRESS_SPACE_LIMIT_32_BIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell us if the device supports 64 bits architecture
|
||||
* @return If the device supports 64 bits architecture
|
||||
|
||||
@@ -50,6 +50,8 @@ import com.google.gson.GsonBuilder;
|
||||
import net.kdt.pojavlaunch.lifecycle.ContextExecutor;
|
||||
import net.kdt.pojavlaunch.lifecycle.ContextExecutorTask;
|
||||
import net.kdt.pojavlaunch.lifecycle.LifecycleAwareAlertDialog;
|
||||
import net.kdt.pojavlaunch.memory.MemoryHoleFinder;
|
||||
import net.kdt.pojavlaunch.memory.SelfMapsParser;
|
||||
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
|
||||
import net.kdt.pojavlaunch.multirt.Runtime;
|
||||
import net.kdt.pojavlaunch.plugins.FFmpegPlugin;
|
||||
@@ -170,9 +172,20 @@ public final class Tools {
|
||||
public static void launchMinecraft(final AppCompatActivity activity, MinecraftAccount minecraftAccount,
|
||||
MinecraftProfile minecraftProfile, String versionId, int versionJavaRequirement) throws Throwable {
|
||||
int freeDeviceMemory = getFreeDeviceMemory(activity);
|
||||
int freeAddressSpace = getMaxContinousAddressSpaceSize();
|
||||
int localeString;
|
||||
Log.i("MemStat", "Free RAM: "+freeDeviceMemory+" Addressable: "+freeAddressSpace);
|
||||
if(freeDeviceMemory > freeAddressSpace && freeAddressSpace != -1) {
|
||||
freeDeviceMemory = freeAddressSpace;
|
||||
localeString = R.string.address_memory_warning_msg;
|
||||
} else {
|
||||
localeString = R.string.memory_warning_msg;
|
||||
}
|
||||
|
||||
if(LauncherPreferences.PREF_RAM_ALLOCATION > freeDeviceMemory) {
|
||||
int finalDeviceMemory = freeDeviceMemory;
|
||||
LifecycleAwareAlertDialog.DialogCreator dialogCreator = (dialog, builder) ->
|
||||
builder.setMessage(activity.getString(R.string.memory_warning_msg, freeDeviceMemory, LauncherPreferences.PREF_RAM_ALLOCATION))
|
||||
builder.setMessage(activity.getString(localeString, finalDeviceMemory, LauncherPreferences.PREF_RAM_ALLOCATION))
|
||||
.setPositiveButton(android.R.string.ok, (d, w)->{});
|
||||
|
||||
if(LifecycleAwareAlertDialog.haltOnDialog(activity.getLifecycle(), activity, dialogCreator)) {
|
||||
@@ -923,6 +936,23 @@ public final class Tools {
|
||||
return (int) (memInfo.availMem / 1048576L);
|
||||
}
|
||||
|
||||
private static int getMaxContinuousAddressSpaceSize0() throws Exception{
|
||||
MemoryHoleFinder memoryHoleFinder = new MemoryHoleFinder();
|
||||
new SelfMapsParser(memoryHoleFinder).run();
|
||||
long largestHole = memoryHoleFinder.getLargestHole();
|
||||
if(largestHole == -1) return -1;
|
||||
else return (int)(largestHole / 1048576L);
|
||||
}
|
||||
|
||||
public static int getMaxContinousAddressSpaceSize() {
|
||||
try {
|
||||
return getMaxContinuousAddressSpaceSize0();
|
||||
}catch (Exception e){
|
||||
Log.w("Tools", "Failed to find the largest uninterrupted address space");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDisplayFriendlyRes(int displaySideRes, float scaling){
|
||||
displaySideRes *= scaling;
|
||||
if(displaySideRes % 2 != 0) displaySideRes --;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.kdt.pojavlaunch.memory;
|
||||
|
||||
import net.kdt.pojavlaunch.Architecture;
|
||||
|
||||
public class MemoryHoleFinder implements SelfMapsParser.Callback {
|
||||
private long mPreviousEnd = 0;
|
||||
private long mLargestHole = -1;
|
||||
private final long mAddressingLimit = Architecture.getAddressSpaceLimit();
|
||||
@Override
|
||||
public boolean process(long begin, long end, String wholeLine) {
|
||||
if(begin >= mAddressingLimit) begin = mAddressingLimit;
|
||||
long holeSize = begin - mPreviousEnd;
|
||||
if(mLargestHole < holeSize) mLargestHole = holeSize;
|
||||
if(begin == mAddressingLimit) return false;
|
||||
mPreviousEnd = end;
|
||||
return true;
|
||||
}
|
||||
|
||||
public long getLargestHole() {
|
||||
return mLargestHole;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.kdt.pojavlaunch.memory;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class SelfMapsParser {
|
||||
private final Callback mCallback;
|
||||
public SelfMapsParser(Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
public void run() throws IOException, NumberFormatException {
|
||||
try (FileInputStream fileInputStream = new FileInputStream("/proc/self/maps")) {
|
||||
Scanner scanner = new Scanner(fileInputStream);
|
||||
while(scanner.hasNextLine()) {
|
||||
if(!forEachLine(scanner.nextLine())) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean forEachLine(String line) throws NumberFormatException {
|
||||
int firstSpaceIndex = line.indexOf(' ');
|
||||
String addresses = line.substring(0, firstSpaceIndex);
|
||||
String[] addressArray = addresses.split("-");
|
||||
if(addressArray.length < 2) return true;
|
||||
long begin = Long.parseLong(addressArray[0], 16);
|
||||
long end = Long.parseLong(addressArray[1], 16);
|
||||
return mCallback.process(begin, end, line);
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
boolean process(long startAddress, long endAddress, String wholeLine);
|
||||
}
|
||||
}
|
||||
@@ -172,6 +172,7 @@
|
||||
<string name="customctrl_forward_lock">Forward lock</string>
|
||||
<string name="customctrl_absolute_tracking">Absolute finger tracking</string>
|
||||
<string name="memory_warning_msg">The current amount of free RAM (%d) is lower than allocated RAM (%d), which may lead to crashes. Change the allocation if the game crashes.</string>
|
||||
<string name="address_memory_warning_msg">The current amount of free addressable RAM space (%d) is lower than the allocated RAM (%d), which will lead to crashes. Change the allocation if the game crashes.</string>
|
||||
<string name="mcl_memory_allocation">Memory allocation</string>
|
||||
<string name="mcl_memory_allocation_subtitle">Controls how much memory is given to Minecraft.</string>
|
||||
<string name="multirt_runtime_corrupt">Corrupted Java Runtime</string>
|
||||
|
||||
Reference in New Issue
Block a user