mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-06-17 06:11:06 +00:00
Forgot those
This commit is contained in:
@@ -31,7 +31,6 @@ import com.volmit.iris.core.nms.INMS;
|
|||||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||||
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
||||||
import com.volmit.iris.core.safeguard.ServerBootSFG;
|
import com.volmit.iris.core.safeguard.ServerBootSFG;
|
||||||
import com.volmit.iris.core.service.HotDropWorldSVC;
|
|
||||||
import com.volmit.iris.core.service.StudioSVC;
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.EnginePanic;
|
import com.volmit.iris.engine.EnginePanic;
|
||||||
@@ -474,8 +473,6 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
UtilsSFG.SupportedServerSoftware();
|
UtilsSFG.SupportedServerSoftware();
|
||||||
UtilsSFG.printIncompatibleWarnings();
|
UtilsSFG.printIncompatibleWarnings();
|
||||||
UtilsSFG.unstablePrompt();
|
UtilsSFG.unstablePrompt();
|
||||||
HotDropWorldSVC hotDropWorldSVC = new HotDropWorldSVC(this);
|
|
||||||
hotDropWorldSVC.start();
|
|
||||||
|
|
||||||
autoStartStudio();
|
autoStartStudio();
|
||||||
ServerBootSFG.CheckIrisWorlds();
|
ServerBootSFG.CheckIrisWorlds();
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* 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 com.volmit.iris.core.commands;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||||
|
import com.volmit.iris.util.decree.DecreeExecutor;
|
||||||
|
import com.volmit.iris.util.decree.DecreeOrigin;
|
||||||
|
import com.volmit.iris.util.decree.annotations.Decree;
|
||||||
|
import com.volmit.iris.util.decree.annotations.Param;
|
||||||
|
import com.volmit.iris.util.format.C;
|
||||||
|
import com.volmit.iris.util.format.Form;
|
||||||
|
import com.volmit.iris.util.mantle.Mantle;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
@Decree(name = "Developer", origin = DecreeOrigin.BOTH, description = "Iris World Manager", aliases = {"dev"})
|
||||||
|
public class CommandDeveloper implements DecreeExecutor {
|
||||||
|
|
||||||
|
@Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, sync = true)
|
||||||
|
public void EngineStatus(
|
||||||
|
@Param(description = "World")
|
||||||
|
World world
|
||||||
|
) {
|
||||||
|
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||||
|
sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||||
|
if(engine != null) {
|
||||||
|
long lastUseSize = engine.getMantle().getLastUseMapMemoryUsage();
|
||||||
|
long outputToUnload = engine.getMantle().getToUnload();
|
||||||
|
|
||||||
|
Iris.info("-------------------------");
|
||||||
|
Iris.info(C.DARK_PURPLE + "Engine Status");
|
||||||
|
Iris.info(C.DARK_PURPLE + "Tectonic Plates: " + C.LIGHT_PURPLE + engine.getMantle().getLoadedRegionCount());
|
||||||
|
Iris.info(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + outputToUnload);
|
||||||
|
Iris.info(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
|
||||||
|
Iris.info(C.DARK_PURPLE + "LastUse Size: " + C.LIGHT_PURPLE + Form.mem(lastUseSize) + " MB");
|
||||||
|
Iris.info("-------------------------");
|
||||||
|
} else {
|
||||||
|
Iris.info(C.RED + "Engine is null!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -69,6 +69,7 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
private CommandEdit edit;
|
private CommandEdit edit;
|
||||||
private CommandFind find;
|
private CommandFind find;
|
||||||
private CommandWorldManager manager;
|
private CommandWorldManager manager;
|
||||||
|
private CommandDeveloper developer;
|
||||||
|
|
||||||
public static @Getter String BenchDimension;
|
public static @Getter String BenchDimension;
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,28 @@ import com.google.gson.JsonParseException;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.util.SFG.WorldHandlerSFG;
|
import com.volmit.iris.util.SFG.WorldHandlerSFG;
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
|
import com.volmit.iris.util.plugin.IrisService;
|
||||||
import com.volmit.iris.util.scheduling.Looper;
|
import com.volmit.iris.util.scheduling.Looper;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
public class HotDropWorldSVC extends Looper {
|
public class HotDropWorldSVC extends Looper implements IrisService {
|
||||||
private WatchService watchService;
|
private WatchService watchService;
|
||||||
private JavaPlugin plugin;
|
private JavaPlugin plugin;
|
||||||
|
|
||||||
public HotDropWorldSVC(JavaPlugin plugin) {
|
@Override
|
||||||
this.plugin = plugin;
|
public void onEnable() {
|
||||||
|
this.plugin = Iris.instance; // Assuming Iris.instance is your plugin instance
|
||||||
|
initializeWatchService();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeWatchService() {
|
||||||
try {
|
try {
|
||||||
this.watchService = FileSystems.getDefault().newWatchService();
|
this.watchService = FileSystems.getDefault().newWatchService();
|
||||||
Path path = Paths.get(Bukkit.getWorldContainer().getAbsolutePath());
|
Path path = Paths.get(Bukkit.getWorldContainer().getAbsolutePath());
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package com.volmit.iris.core.service;
|
||||||
|
|
||||||
|
import java.nio.file.*;
|
||||||
|
import static java.nio.file.StandardWatchEventKinds.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.util.SFG.WorldHandlerSFG;
|
||||||
|
import com.volmit.iris.util.format.C;
|
||||||
|
import com.volmit.iris.util.misc.getHardware;
|
||||||
|
import com.volmit.iris.util.plugin.IrisService;
|
||||||
|
import com.volmit.iris.util.scheduling.Looper;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public class MemoryLeakSVC extends Looper implements IrisService {
|
||||||
|
private WatchService watchService;
|
||||||
|
private JavaPlugin plugin;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
//Iris.info("Enabled Mem Leak Detection thing wow it actually worked");
|
||||||
|
//this.plugin = Iris.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long loop() {
|
||||||
|
try {
|
||||||
|
if (getHardware.getAvailableProcessMemory() < 50){
|
||||||
|
PrintMemoryLeakDetected();
|
||||||
|
for (World world : Bukkit.getWorlds()) {
|
||||||
|
if (IrisToolbelt.isIrisWorld(world)){
|
||||||
|
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||||
|
if (engine.getMantle().getLoadedRegionCount() > 0){
|
||||||
|
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||||
|
Iris.info(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Iris.info(C.GREEN + "Unloading world: " + world.getName());
|
||||||
|
try {
|
||||||
|
IrisToolbelt.evacuate(world);
|
||||||
|
Bukkit.unloadWorld(world, false);
|
||||||
|
Iris.info(C.GREEN + "World unloaded successfully.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Iris.info(C.RED + "Failed to unload the world: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
public void PrintMemoryLeakDetected(){
|
||||||
|
Iris.info(C.DARK_RED + "--==< MEMORY LEAK DETECTED >==--");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -257,6 +257,9 @@ public interface EngineMantle extends IObjectPlacer {
|
|||||||
default int getLoadedRegionCount() {
|
default int getLoadedRegionCount() {
|
||||||
return getMantle().getLoadedRegionCount();
|
return getMantle().getLoadedRegionCount();
|
||||||
}
|
}
|
||||||
|
default long getLastUseMapMemoryUsage(){
|
||||||
|
return getMantle().LastUseMapMemoryUsage();
|
||||||
|
}
|
||||||
|
|
||||||
MantleJigsawComponent getJigsawComponent();
|
MantleJigsawComponent getJigsawComponent();
|
||||||
|
|
||||||
@@ -288,4 +291,8 @@ public interface EngineMantle extends IObjectPlacer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default long getToUnload(){
|
||||||
|
return getMantle().ToUnloadTectonic();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.volmit.iris.util.function.Consumer4;
|
|||||||
import com.volmit.iris.util.math.M;
|
import com.volmit.iris.util.math.M;
|
||||||
import com.volmit.iris.util.matter.Matter;
|
import com.volmit.iris.util.matter.Matter;
|
||||||
import com.volmit.iris.util.matter.MatterSlice;
|
import com.volmit.iris.util.matter.MatterSlice;
|
||||||
|
import com.volmit.iris.util.misc.getHardware;
|
||||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||||
import com.volmit.iris.util.parallel.HyperLock;
|
import com.volmit.iris.util.parallel.HyperLock;
|
||||||
import com.volmit.iris.util.parallel.MultiBurst;
|
import com.volmit.iris.util.parallel.MultiBurst;
|
||||||
@@ -45,16 +46,18 @@ import org.bukkit.Chunk;
|
|||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The mantle can store any type of data slice anywhere and manage regions & IO on it's own.
|
* The mantle can store any type of data slice anywhere and manage regions & IO on it's own.
|
||||||
* This class is fully thread safe read & writeNodeData
|
* This class is fully thread safe read & writeNodeData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Mantle {
|
public class Mantle {
|
||||||
private final File dataFolder;
|
private final File dataFolder;
|
||||||
private final int worldHeight;
|
private final int worldHeight;
|
||||||
@@ -66,6 +69,11 @@ public class Mantle {
|
|||||||
private final AtomicBoolean closed;
|
private final AtomicBoolean closed;
|
||||||
private final MultiBurst ioBurst;
|
private final MultiBurst ioBurst;
|
||||||
private final AtomicBoolean io;
|
private final AtomicBoolean io;
|
||||||
|
private final Object gcMonitor = new Object();
|
||||||
|
long apm = getHardware.getAvailableProcessMemory();
|
||||||
|
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||||
|
int tectonicLimitBeforeOutMemory;
|
||||||
|
double tectonicLimit = 30;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new mantle
|
* Create a new mantle
|
||||||
@@ -374,45 +382,92 @@ public class Mantle {
|
|||||||
Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath());
|
Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estimates the memory usage of the lastUse map.
|
||||||
|
*
|
||||||
|
* @return Estimated memory usage in bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public long LastUseMapMemoryUsage() {
|
||||||
|
long numberOfEntries = lastUse.size();
|
||||||
|
long bytesPerEntry = Long.BYTES * 2;
|
||||||
|
return numberOfEntries * bytesPerEntry;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save & unload regions that have not been used for more than the
|
* Save & unload regions that have not been used for more than the
|
||||||
* specified amount of milliseconds
|
* specified amount of milliseconds
|
||||||
*
|
*
|
||||||
* @param idleDuration the duration
|
* @param baseIdleDuration the duration
|
||||||
*/
|
*/
|
||||||
public synchronized void trim(long idleDuration) {
|
|
||||||
|
AtomicInteger FakeToUnload = new AtomicInteger(0);
|
||||||
|
|
||||||
|
|
||||||
|
public synchronized void trim(long baseIdleDuration) {
|
||||||
if (closed.get()) {
|
if (closed.get()) {
|
||||||
throw new RuntimeException("The Mantle is closed");
|
throw new RuntimeException("The Mantle is closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double adjustedIdleDuration = baseIdleDuration;
|
||||||
|
|
||||||
|
if (loadedRegions.size() > tectonicLimit) {
|
||||||
|
adjustedIdleDuration = Math.max(adjustedIdleDuration - ( 1000 * (loadedRegions.size() - tectonicLimit) * 1.35), 4000);
|
||||||
|
}
|
||||||
|
|
||||||
io.set(true);
|
io.set(true);
|
||||||
Iris.debug("Trimming Tectonic Plates older than " + Form.duration((double) idleDuration, 0));
|
|
||||||
unload.clear();
|
|
||||||
|
|
||||||
for (Long i : lastUse.keySet()) {
|
try {
|
||||||
hyperLock.withLong(i, () -> {
|
Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration, 0));
|
||||||
if (M.ms() - lastUse.get(i) >= idleDuration) {
|
Set<Long> toUnload = new HashSet<>();
|
||||||
unload.add(i);
|
|
||||||
}
|
for (Long i : lastUse.keySet()) {
|
||||||
});
|
double finalAdjustedIdleDuration = adjustedIdleDuration;
|
||||||
|
hyperLock.withLong(i, () -> {
|
||||||
|
if (M.ms() - lastUse.get(i) >= finalAdjustedIdleDuration) {
|
||||||
|
toUnload.add(i);
|
||||||
|
FakeToUnload.addAndGet(1);
|
||||||
|
Iris.debug("Tectonic Region added to unload");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a thread pool to handle unloading tasks
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||||
|
|
||||||
|
for (Long i : toUnload) {
|
||||||
|
executor.submit(() -> {
|
||||||
|
hyperLock.withLong(i, () -> {
|
||||||
|
TectonicPlate m = loadedRegions.get(i);
|
||||||
|
if (m != null) {
|
||||||
|
try {
|
||||||
|
m.write(fileForRegion(dataFolder, i));
|
||||||
|
loadedRegions.remove(i);
|
||||||
|
lastUse.remove(i);
|
||||||
|
Iris.debug("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(i) + " " + Cache.keyZ(i));
|
||||||
|
FakeToUnload.addAndGet(-1);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown the executor and wait for tasks to complete
|
||||||
|
executor.shutdown();
|
||||||
|
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
io.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Long i : unload) {
|
|
||||||
hyperLock.withLong(i, () -> {
|
|
||||||
TectonicPlate m = loadedRegions.remove(i);
|
|
||||||
lastUse.remove(i);
|
|
||||||
|
|
||||||
try {
|
|
||||||
m.write(fileForRegion(dataFolder, i));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
Iris.debug("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(i) + " " + Cache.keyZ(i));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
io.set(false);
|
|
||||||
}
|
}
|
||||||
|
public long ToUnloadTectonic(){
|
||||||
|
return FakeToUnload.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This retreives a future of the Tectonic Plate at the given coordinates.
|
* This retreives a future of the Tectonic Plate at the given coordinates.
|
||||||
@@ -443,7 +498,7 @@ public class Mantle {
|
|||||||
try {
|
try {
|
||||||
return getSafe(x, z).get();
|
return getSafe(x, z).get();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread interruption (hotload?)");
|
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)");
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)");
|
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)");
|
||||||
|
|||||||
@@ -22,6 +22,20 @@ public class getHardware {
|
|||||||
long maxMemory = Runtime.getRuntime().maxMemory() / (1024 * 1024);
|
long maxMemory = Runtime.getRuntime().maxMemory() / (1024 * 1024);
|
||||||
return maxMemory;
|
return maxMemory;
|
||||||
}
|
}
|
||||||
|
public static long getProcessUsedMemory() {
|
||||||
|
Runtime runtime = Runtime.getRuntime();
|
||||||
|
|
||||||
|
long totalMemory = runtime.totalMemory();
|
||||||
|
long freeMemory = runtime.freeMemory();
|
||||||
|
long usedMemory = totalMemory - freeMemory;
|
||||||
|
|
||||||
|
return usedMemory / (1024 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getAvailableProcessMemory(){
|
||||||
|
long availableMemory = getHardware.getProcessMemory() - getHardware.getProcessUsedMemory();
|
||||||
|
return availableMemory;
|
||||||
|
}
|
||||||
|
|
||||||
public static String getCPUModel() {
|
public static String getCPUModel() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user