Skip to content

Commit

Permalink
Memory usage improvements for transform cache (#336)
Browse files Browse the repository at this point in the history
* Add system property to enable useTempFile in ZipFS

This avoids storing data in memory but slows down cache building,
so we gate it behind a system property that's off by default

* Delete previous transform cache file if recreating

* Avoid storing all class bytes in a map at once for internals hider transformation
  • Loading branch information
embeddedt authored Jul 28, 2023
1 parent 039f340 commit bd1630f
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ private static QuiltZipPath checkTransformCache(Path transformCacheFolder, Map<S
QuiltZipPath inner = fs.getRoot();
if (!FasterFiles.isRegularFile(inner.resolve(FILE_TRANSFORM_COMPLETE))) {
Log.info(LogCategory.CACHE, "Not reusing previous transform cache since it's incomplete!");
// delete the previous transform cache to prevent FileAlreadyExistsException later
try { Files.deleteIfExists(cacheFile); } catch(IOException ignored) {}
return null;
}
Path optionFile = inner.resolve("options.txt");
Expand Down Expand Up @@ -312,17 +314,21 @@ private static void populateTransformCache(Path root, List<ModLoadOption> modLis
}

InternalsHiderTransform internalsHider = new InternalsHiderTransform(InternalsHiderTransform.Target.MOD);
Map<Path, ClassData> classes = new HashMap<>();
Map<Path, ModLoadOption> classes = new HashMap<>();

// the double read is necessary to avoid storing all classes in memory at once, and thus having memory complexity
// proportional to mod count

forEachClassFile(root, modList, (mod, file) -> {
byte[] classBytes = Files.readAllBytes(file);
classes.put(file, new ClassData(mod, classBytes));
classes.put(file, mod);
internalsHider.scanClass(mod, file, classBytes);
return null;
});

for (Map.Entry<Path, ClassData> entry : classes.entrySet()) {
byte[] newBytes = internalsHider.run(entry.getValue().mod, entry.getValue().classBytes);
for (Map.Entry<Path, ModLoadOption> entry : classes.entrySet()) {
byte[] classBytes = Files.readAllBytes(entry.getKey());
byte[] newBytes = internalsHider.run(entry.getValue(), classBytes);
if (newBytes != null) {
Files.write(entry.getKey(), newBytes);
}
Expand Down
15 changes: 12 additions & 3 deletions src/main/java/org/quiltmc/loader/impl/util/FileSystemUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipError;

Expand Down Expand Up @@ -56,8 +56,17 @@ public void close() throws IOException {

private FileSystemUtil() { }

private static final Map<String, String> jfsArgsCreate = Collections.singletonMap("create", "true");
private static final Map<String, String> jfsArgsEmpty = Collections.emptyMap();
private static final Map<String, Object> jfsArgsCreate = new HashMap<>();
private static final Map<String, Object> jfsArgsEmpty = new HashMap<>();

static {
jfsArgsCreate.put("create", "true");
if(Boolean.getBoolean(SystemProperties.USE_ZIPFS_TEMP_FILE)) {
// must be Boolean.TRUE for Java 8
jfsArgsCreate.put("useTempFile", Boolean.TRUE);
jfsArgsEmpty.put("useTempFile", Boolean.TRUE);
}
}

public static FileSystemDelegate getJarFileSystem(Path path, boolean create) throws IOException {
return getJarFileSystem(path.toUri(), create);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public final class SystemProperties {
public static final String DISABLE_OPTIMIZED_COMPRESSED_TRANSFORM_CACHE = "loader.transform_cache.disable_optimised_compression";
public static final String DISABLE_PRELOAD_TRANSFORM_CACHE = "loader.transform_cache.disable_preload";
public static final String LOG_CACHE_KEY_CHANGES = "loader.transform_cache.log_changed_keys";
// enable useTempFile in ZipFileSystem, reduces memory usage when writing transform cache at the cost of speed
public static final String USE_ZIPFS_TEMP_FILE = "loader.zipfs.use_temp_file";
public static final String DISABLE_BEACON = "loader.disable_beacon";

private SystemProperties() {
Expand Down

0 comments on commit bd1630f

Please sign in to comment.