Skip to content

Commit

Permalink
Feat[launcher]: check whether user is running out of addressable memo…
Browse files Browse the repository at this point in the history
…ry for Java
  • Loading branch information
artdeell committed Jul 19, 2024
1 parent 992ac0f commit 2982852
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 31 additions & 1 deletion app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
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;
Expand Down Expand Up @@ -170,9 +172,20 @@ public static void initContextConstants(Context ctx){
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)) {
Expand Down Expand Up @@ -923,6 +936,23 @@ public static int getFreeDeviceMemory(Context ctx){
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 --;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
1 change: 1 addition & 0 deletions app_pojavlauncher/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down

0 comments on commit 2982852

Please sign in to comment.