Skip to content

Commit

Permalink
Fix memory leak
Browse files Browse the repository at this point in the history
  • Loading branch information
Meeples10 committed Jun 14, 2023
1 parent 939035e commit c84e8ef
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 65 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ MCResourceAnalyzer gathers data from Minecraft region files to determine the emp

1. Clone the repository and build it with Maven or [download the latest release here](https://github.com/Meeples10/MCResourceAnalyzer/releases).
2. If your world was generated with a version after Beta 1.3, use the `region` directory from your Minecraft world as the program's input.
If the world was generated with a version between Infdev 20100327 and Beta 1.2, use the entire world directory to `region` as the program's input.
If the world was generated with Indev, rename the save file to `world.mclevel` and copy it to the same directory as the program.
If the world was generated with a version between Infdev 20100327 and Beta 1.2, use the entire world directory as the input.
If the world was generated with Indev, use the `world.mclevel` file as the input.
3. Run the program with `java -jar mc-resource-analyzer-x.x.x.jar [options...] [input path]`. After analyzing the world, the program will create a file in the same directory named `data.csv`.

Note that the numbers for `minecraft:air` may be inaccurate at high Y values due to the way Minecraft stores chunks.
Expand Down Expand Up @@ -46,7 +46,7 @@ java -jar mc-resource-analyzer-x.x.x.jar [-hHmsStV] [-B=PATH] [-M=PATH] [-o=STRI

### Version compatibility

MCResourceAnalyzer 1.2.0 can analyze worlds generated with any version of Minecraft: Java Edition between Indev 0.31 20100122 and 1.20.1.
MCResourceAnalyzer 1.2.1 can analyze worlds generated with any version of Minecraft: Java Edition between Indev 0.31 20100122 and 1.20.1.

Note that Indev worlds with the `Long` and `Deep` world shapes are not supported.

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<groupId>io.github.meeples10.mcresourceanalyzer</groupId>
<artifactId>mc-resource-analyzer</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
<packaging>jar</packaging>

<name>MCResourceAnalyzer</name>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package io.github.meeples10.mcresourceanalyzer;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class Analysis {
public Map<String, Long> blocks = new HashMap<String, Long>();
public Map<String, HashMap<Integer, Long>> heights = new HashMap<String, HashMap<Integer, Long>>();
public Map<String, Long> blocks = new Hashtable<>();
public Map<String, Hashtable<Integer, Long>> heights = new Hashtable<>();
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,52 @@
package io.github.meeples10.mcresourceanalyzer;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;

public abstract class AnalyzerThread extends Thread {
final RegionAnalyzer ra;
final Region r;
final Set<Analysis> analyses = new HashSet<>();

public AnalyzerThread(Region region) {
public AnalyzerThread(RegionAnalyzer ra, Region region) {
this.ra = ra;
r = region;
setName(r.name);
}

public abstract void run();
public void run() {
process();
ra.add(combineAnalyses());
}

public abstract void process();

private Analysis combineAnalyses() {
Analysis out = new Analysis();
for(Analysis a : analyses) {
for(String blockName : a.blocks.keySet()) {
long count = a.blocks.get(blockName);
if(out.blocks.containsKey(blockName)) {
out.blocks.put(blockName, out.blocks.get(blockName) + count);
} else {
out.blocks.put(blockName, count);
}
}
for(String blockName : a.heights.keySet()) {
if(!out.heights.containsKey(blockName)) {
out.heights.put(blockName, new Hashtable<Integer, Long>());
}
for(int y : a.heights.get(blockName).keySet()) {
long count = a.heights.get(blockName).get(y);
if(out.heights.get(blockName).containsKey(y)) {
out.heights.get(blockName).put(y, out.heights.get(blockName).get(y) + count);
} else {
out.heights.get(blockName).put(y, count);
}
}
}
}
return out;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -19,8 +19,8 @@
public abstract class RegionAnalyzer {
private Version version;
public int chunkCount = 0;
public Map<String, Long> blockCounter = new HashMap<String, Long>();
public Map<String, HashMap<Integer, Long>> heightCounter = new HashMap<String, HashMap<Integer, Long>>();
public Map<String, Long> blockCounter = new Hashtable<>();
public Map<String, Hashtable<Integer, Long>> heightCounter = new Hashtable<>();
private long firstStartTime;
public long duration;
List<Region> regions = new ArrayList<>();
Expand Down Expand Up @@ -56,29 +56,12 @@ public void run(File input) {
pool.submit(t);
}
pool.shutdown();
threads.clear();
try {
pool.awaitTermination(100, TimeUnit.DAYS);
} catch(InterruptedException e) {
e.printStackTrace();
}
for(AnalyzerThread t : threads) {
for(Analysis a : t.analyses) {
for(String s : a.blocks.keySet()) {
blockCounter.put(s, blockCounter.getOrDefault(s, 0L) + a.blocks.get(s));
}
for(String s : a.heights.keySet()) {
if(heightCounter.containsKey(s)) {
Map<Integer, Long> existing = heightCounter.get(s);
Map<Integer, Long> heights = a.heights.get(s);
for(int i : heights.keySet()) {
existing.put(i, existing.getOrDefault(i, 0L) + heights.get(i));
}
} else {
heightCounter.put(s, a.heights.get(s));
}
}
}
}
}

duration = System.currentTimeMillis() - getStartTime();
Expand Down Expand Up @@ -195,7 +178,7 @@ public String generateTable(double totalBlocks, double totalExcludingAir) {
data.append("<table>\n");
}
data.append("<tr><th>id</th><th>");
for(int i = minY; i < maxY; i++) {
for(int i = minY; i <= maxY; i++) {
data.append(i);
data.append("</th><th>");
}
Expand All @@ -209,7 +192,7 @@ public String generateTable(double totalBlocks, double totalExcludingAir) {
data.append("<td>");
data.append(Main.modernizeIDs ? Main.getStringID(key) : key);
data.append("</td>");
for(int i = minY; i < maxY; i++) {
for(int i = minY; i <= maxY; i++) {
if(!heightCounter.get(key).containsKey(i)) {
data.append("<td>0</td>");
} else {
Expand Down Expand Up @@ -256,7 +239,7 @@ static boolean mergeStates(byte id) {
static void airHack(Analysis a, int sectionY, String airID) {
if(Main.allowHack && sectionY < 15) {
if(!a.blocks.containsKey(airID)) a.blocks.put(airID, 0L);
if(!a.heights.containsKey(airID)) a.heights.put(airID, new HashMap<Integer, Long>());
if(!a.heights.containsKey(airID)) a.heights.put(airID, new Hashtable<Integer, Long>());
for(; sectionY < 16; sectionY++) {
a.blocks.put(airID, a.blocks.get(airID) + 4096L);
for(int y = sectionY * 16; y < sectionY * 16 + 16; y++) {
Expand All @@ -270,7 +253,7 @@ static void airHack(Analysis a, int sectionY, String airID) {
}
}

int getMinimumY() {
private int getMinimumY() {
int min = Integer.MAX_VALUE;
for(Map<Integer, Long> map : heightCounter.values()) {
for(int i : map.keySet()) {
Expand All @@ -286,7 +269,7 @@ int getMinimumY() {
}
}

int getMaximumY() {
private int getMaximumY() {
int max = Integer.MIN_VALUE;
for(Map<Integer, Long> map : heightCounter.values()) {
for(int i : map.keySet()) {
Expand All @@ -296,12 +279,29 @@ int getMaximumY() {
}
}
if(version == Version.INDEV || version == Version.ALPHA || version == Version.MCREGION) {
return 128;
return 127;
} else {
return max > 255 ? max : 255;
}
}

synchronized void add(Analysis a) {
for(String s : a.blocks.keySet()) {
blockCounter.put(s, blockCounter.getOrDefault(s, 0L) + a.blocks.get(s));
}
for(String s : a.heights.keySet()) {
if(heightCounter.containsKey(s)) {
Map<Integer, Long> existing = heightCounter.get(s);
Map<Integer, Long> heights = a.heights.get(s);
for(int i : heights.keySet()) {
existing.put(i, existing.getOrDefault(i, 0L) + heights.get(i));
}
} else {
heightCounter.put(s, a.heights.get(s));
}
}
}

public enum Version {
ANVIL_118(RegionAnalyzerAnvil118.class, true),
ANVIL_2021(RegionAnalyzerAnvil2021.class, true),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;

import net.minecraft.nbt.CompressedStreamTools;
Expand Down Expand Up @@ -89,7 +89,7 @@ private void analyzeChunk(byte[] blocks, byte[] data) {
a.blocks.put(blockName, 1L);
}
if(!a.heights.containsKey(blockName)) {
a.heights.put(blockName, new HashMap<Integer, Long>());
a.heights.put(blockName, new Hashtable<Integer, Long>());
}
if(a.heights.get(blockName).containsKey(y)) {
a.heights.get(blockName).put(y, a.heights.get(blockName).get(y) + 1L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;

import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
Expand Down Expand Up @@ -40,9 +40,8 @@ public void findChunks(File regionDir) {
@Override
public void analyze() {
for(Region r : regions) {
threads.add(new AnalyzerThread(r) {
@Override
public void run() {
threads.add(new AnalyzerThread(this, r) {
public void process() {
for(Chunk c : r.chunks) {
try {
Analysis a = processRegion(r.file, c.x(), c.z());
Expand Down Expand Up @@ -98,7 +97,7 @@ private Analysis analyzeChunk(NBTTagList sections) {
a.blocks.put(blockName, 1L);
}
if(!a.heights.containsKey(blockName)) {
a.heights.put(blockName, new HashMap<Integer, Long>());
a.heights.put(blockName, new Hashtable<Integer, Long>());
}
if(a.heights.get(blockName).containsKey(actualY)) {
a.heights.get(blockName).put(actualY, a.heights.get(blockName).get(actualY) + 1L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;

import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
Expand Down Expand Up @@ -39,9 +39,8 @@ public void findChunks(File regionDir) {
@Override
public void analyze() {
for(Region r : regions) {
threads.add(new AnalyzerThread(r) {
@Override
public void run() {
threads.add(new AnalyzerThread(this, r) {
public void process() {
for(Chunk c : r.chunks) {
try {
Analysis a = processRegion(r.file, c.x(), c.z());
Expand Down Expand Up @@ -107,7 +106,7 @@ private Analysis analyzeChunk(NBTTagList sections) {
a.blocks.put(blockName, 1L);
}
if(!a.heights.containsKey(blockName)) {
a.heights.put(blockName, new HashMap<Integer, Long>());
a.heights.put(blockName, new Hashtable<Integer, Long>());
}
if(a.heights.get(blockName).containsKey(actualY)) {
a.heights.get(blockName).put(actualY, a.heights.get(blockName).get(actualY) + 1L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;

import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
Expand Down Expand Up @@ -42,9 +42,8 @@ public void analyze() {
// The air hack does not seem to work for this version
Main.allowHack = false;
for(Region r : regions) {
threads.add(new AnalyzerThread(r) {
@Override
public void run() {
threads.add(new AnalyzerThread(this, r) {
public void process() {
for(Chunk c : r.chunks) {
try {
Analysis a = processRegion(r.file, c.x(), c.z());
Expand Down Expand Up @@ -100,7 +99,7 @@ private Analysis analyzeChunk(NBTTagList sections) {
a.blocks.put(blockName, 1L);
}
if(!a.heights.containsKey(blockName)) {
a.heights.put(blockName, new HashMap<Integer, Long>());
a.heights.put(blockName, new Hashtable<Integer, Long>());
}
if(a.heights.get(blockName).containsKey(actualY)) {
a.heights.get(blockName).put(actualY, a.heights.get(blockName).get(actualY) + 1L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;

import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
Expand Down Expand Up @@ -40,9 +40,8 @@ public void findChunks(File regionDir) {
@Override
public void analyze() {
for(Region r : regions) {
threads.add(new AnalyzerThread(r) {
@Override
public void run() {
threads.add(new AnalyzerThread(this, r) {
public void process() {
for(Chunk c : r.chunks) {
try {
Analysis a = processRegion(r.file, c.x(), c.z());
Expand Down Expand Up @@ -98,7 +97,7 @@ private Analysis analyzeChunk(NBTTagList sections) {
a.blocks.put(blockName, 1L);
}
if(!a.heights.containsKey(blockName)) {
a.heights.put(blockName, new HashMap<Integer, Long>());
a.heights.put(blockName, new Hashtable<Integer, Long>());
}
if(a.heights.get(blockName).containsKey(actualY)) {
a.heights.get(blockName).put(actualY, a.heights.get(blockName).get(actualY) + 1L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;

import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
Expand Down Expand Up @@ -72,7 +72,7 @@ private Analysis analyzeWorld(byte[] blocks, byte[] data, int width, int height)
a.blocks.put(blockName, 1L);
}
if(!a.heights.containsKey(blockName)) {
a.heights.put(blockName, new HashMap<Integer, Long>());
a.heights.put(blockName, new Hashtable<Integer, Long>());
}
if(a.heights.get(blockName).containsKey(y)) {
a.heights.get(blockName).put(y, a.heights.get(blockName).get(y) + 1L);
Expand Down
Loading

0 comments on commit c84e8ef

Please sign in to comment.