Solve exercise 13

This commit is contained in:
Manuel Thalmann 2022-12-20 03:10:24 +01:00
parent a410e816f4
commit c99b0817c0
6 changed files with 511 additions and 0 deletions

View file

@ -0,0 +1,29 @@
package ch.nuth.zhaw.exbox;
/** base class of collectable objects */
public class CObject implements Collectable {
private boolean mark; // to mark object
public CObject next, down;
public String value;
public CObject (String value) {
this.value = value;
}
public void setMark(boolean mark) {
this.mark = mark;
}
public boolean isMarked() {
return mark;
}
public String toString() {
return value;
}
@Override
public boolean equals(Object o) {
return this.getClass() == o.getClass() && this.value.equals(((CObject)o).value);
}
}

View file

@ -0,0 +1,6 @@
package ch.nuth.zhaw.exbox;
public interface Collectable {
void setMark(boolean b);
boolean isMarked();
}

View file

@ -0,0 +1,188 @@
package ch.nuth.zhaw.exbox;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public class Storage {
public static boolean generationalGCActive = true; // in Aufgabe 2 verwendet
public static StringBuffer log = new StringBuffer();
private static List<Collectable> root;
private static List<Collectable> youngHeap;
private static List<Collectable> oldHeap;
public static boolean youngGenerationOnly = true;
static {
clear();
}
public static void clear() {
root = new LinkedList<>();
youngHeap = new LinkedList<>();
// oldHeap erst in Aufgabe 2 verwenden!
oldHeap = new LinkedList<>();
}
/* add root object */
public static void addRoot(Collectable obj) {
root.add(obj);
}
// create a collectable object of class cls
public static Collectable _new(String cls, Object arg) {
Collectable obj = null;
try {
// create an object and call constructor
Constructor<?> cst = Class.forName(getPackage() + cls).getConstructor(arg.getClass());
obj = (Collectable) cst.newInstance(new Object[] { arg });
// add object to heap
youngHeap.add(obj);
log.append("New: ").append(obj).append("\n");
} catch (Exception ex) {
log.append("error creating object ").append(cls).append("\n");
}
return obj;
}
private static String getPackage() {
Package pack = Storage.class.getPackage();
if (pack != null && !pack.getName().equals("")) {
return pack.getName() + ".";
} else {
return "";
}
}
/* remove object from heap */
public static void delete(Collectable obj) {
if (youngHeap.remove(obj)) {
if (generationalGCActive) {
log.append("Delete young heap: ").append(obj).append("\n");
} else {
log.append("Delete heap: ").append(obj).append("\n");
}
} else if (oldHeap.remove(obj)) {
log.append("Delete old heap: ").append(obj).append("\n");
} else {
log.append("error trying to delete not existing object ").append(obj).append("\n");
}
}
/* get all root objects */
public static Iterable<Collectable> getRoot() {
return new LinkedList<>(root);
}
/* get young heap */
public static Iterable<Collectable> getYoungHeap() {
return new LinkedList<>(youngHeap);
}
/* get old heap */
public static Iterable<Collectable> getOldHeap() {
return new LinkedList<>(oldHeap);
}
/* get heap */
public static Iterable<Collectable> getHeap() {
return new LinkedList<>(youngHeap);
}
/* get references to collectables of an object */
public static Iterable<Collectable> getRefs(Collectable obj) {
// get all fields of an object
List<Collectable> fieldList = new LinkedList<>();
for (Field field : obj.getClass().getFields()) {
try {
Object o = field.get(obj);
if (o instanceof Collectable) {
fieldList.add((Collectable) o);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
return fieldList;
}
/* dump an iterator */
public static void dump(String s, Iterable<Collectable> itr) {
log.append(s);
for (Collectable o : itr) {
log.append(" ").append(o);
}
log.append("\n");
}
public static String getLog() {
return log.toString();
}
private static void mark(Collectable cObject) {
// TODO Aufgabe 13.1
if (!cObject.isMarked()) {
cObject.setMark(true);
for (Collectable item : getRefs(cObject)) {
mark(item);
}
}
}
private static void sweep() {
// TODO Aufgabe 13.1 und Aufgabe 13.2
Map<Iterable<Collectable>, Consumer<Collectable>> heaps = new HashMap<>();
Consumer<Collectable> noOp = (item) -> {};
Consumer<Collectable> copy = (item) -> {
youngHeap.remove(item);
oldHeap.add(item);
};
heaps.put(getYoungHeap(), generationalGCActive ? copy : noOp);
if (!youngGenerationOnly) {
heaps.put(getOldHeap(), noOp);
}
for (Map.Entry<Iterable<Collectable>, Consumer<Collectable>> entry : heaps.entrySet()) {
for (Collectable item : entry.getKey()) {
if (!item.isMarked()) {
delete(item);
} else {
item.setMark(false);
entry.getValue().accept(item);
}
}
}
}
public static void gc() {
if (generationalGCActive) {
if (youngGenerationOnly) {
log.append("\nCollector start young generation only\n");
} else {
log.append("\nCollector start young and old generation\n");
}
} else {
log.append("\nCollector start\n");
}
// TODO Aufgabe 13.1 und Aufgabe 13.2
for (Collectable item : getRoot()) {
mark(item);
}
sweep();
if (generationalGCActive) {
youngGenerationOnly = !youngGenerationOnly;
}
log.append("Collector end\n");
}
}

View file

@ -0,0 +1,66 @@
package ch.nuth.zhaw.exbox;
public class TestCObjectServer implements CommandExecutor {
private static CObject new_CObject(Object s) {
return (CObject) Storage._new("CObject", s);
}
static CObject a;
static CObject e;
public String execute (String input) {
run();
return Storage.getLog();
}
private void run() {
a = new_CObject("A");
CObject b = new_CObject("B");
CObject c = new_CObject("C");
CObject d = new_CObject("D");
e = new_CObject("E");
CObject f = new_CObject("F");
CObject g = new_CObject("G");
Storage.addRoot(a);
Storage.addRoot(e);
a.next = b; b.next = c; b.down = a; c.down = d;
e.next = f; f.next = g; g.next = e;
Storage.dump("\nRoots:", Storage.getRoot());
if (Storage.generationalGCActive) {
Storage.dump("\nYoung heap 1:", Storage.getYoungHeap());
Storage.dump("Old heap 1:", Storage.getOldHeap());
} else {
Storage.dump("Heap 1:", Storage.getYoungHeap());
}
Storage.gc();
if (Storage.generationalGCActive) {
Storage.dump("Young heap 2:", Storage.getYoungHeap());
Storage.dump("Old heap 2:", Storage.getOldHeap());
} else {
Storage.dump("Heap 2:", Storage.getYoungHeap());
}
b.next = f;
Storage.gc();
if (Storage.generationalGCActive) {
Storage.dump("Young heap 3:", Storage.getYoungHeap());
Storage.dump("Old heap 3:", Storage.getOldHeap());
} else {
Storage.dump("Heap 3:", Storage.getYoungHeap());
}
f.next = null;
Storage.gc();
if (Storage.generationalGCActive) {
Storage.dump("Young heap 4:", Storage.getYoungHeap());
Storage.dump("Old heap 4:", Storage.getOldHeap());
} else {
Storage.dump("Heap 4:", Storage.getYoungHeap());
}
Storage.gc();
if (Storage.generationalGCActive) {
Storage.dump("Young heap 5:", Storage.getYoungHeap());
Storage.dump("Old heap 5:", Storage.getOldHeap());
} else {
Storage.dump("Heap 5:", Storage.getYoungHeap());
}
}
}

View file

@ -0,0 +1,92 @@
package ch.nuth.zhaw.exbox;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ADS13_1_test {
private CObject new_CObject(Object s) {
return (CObject) Storage._new("CObject", s);
}
static CObject a, d;
CObject b, c, e, f, g;
@BeforeEach
public void setUp() {
Storage.generationalGCActive = false;
Storage.clear();
newObjects();
}
private void testContent(String message, Iterable<Collectable> content, String expected) {
StringBuilder b = new StringBuilder();
content.forEach(b::append);
assertEquals(expected, b.toString(), message);
}
private void newObjects() {
a = new_CObject("A");
b = new_CObject("B");
c = new_CObject("C");
d = new_CObject("D");
e = new_CObject("E");
f = new_CObject("F");
g = new_CObject("G");
Storage.addRoot(a);
Storage.addRoot(d);
a.next = b;
b.next = c;
b.down = a;
c.down = d;
d.next = e;
e.next = f;
f.next = g;
}
@Test
public void testRoot() {
testContent("ROOT", Storage.getRoot(), "AD");
}
@Test
public void testInitialHeap() {
testContent("HEAP1", Storage.getHeap(), "ABCDEFG");
}
@Test
public void testAfterFirstGC() {
Storage.gc();
testContent("HEAP2", Storage.getHeap(), "ABCDEFG");
}
@Test
public void testAfterFirstChangeGC() {
Storage.gc();
e.next = d;
Storage.gc();
testContent("HEAP3", Storage.getHeap(), "ABCDE");
}
@Test
public void testAfterSecondChangeGC() {
Storage.gc();
e.next = d;
Storage.gc();
a.next = null;
Storage.gc();
testContent("HEAP4", Storage.getHeap(), "ADE");
}
@Test
public void testFinalHeap() {
Storage.gc();
e.next = d;
Storage.gc();
a.next = null;
Storage.gc();
Storage.gc();
testContent("HEAP5", Storage.getHeap(), "ADE");
}
}

View file

@ -0,0 +1,130 @@
package ch.nuth.zhaw.exbox;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ADS13_3_test {
private CObject new_CObject(Object s) {
return (CObject) Storage._new("CObject", s);
}
static CObject a, d;
CObject b, c, e, f, g, h;
@BeforeEach
public void setUp() {
Storage.generationalGCActive = true;
Storage.youngGenerationOnly = true;
Storage.clear();
newObjects();
}
private void testContent(String message, Iterable<Collectable> content, String expected) {
StringBuilder b = new StringBuilder();
content.forEach(b::append);
assertEquals(expected, b.toString(), message);
}
private void newObjects() {
a = new_CObject("A");
b = new_CObject("B");
c = new_CObject("C");
d = new_CObject("D");
e = new_CObject("E");
f = new_CObject("F");
g = new_CObject("G");
Storage.addRoot(a);
Storage.addRoot(d);
a.next = b;
b.next = c;
b.down = a;
c.down = d;
d.next = e;
e.next = f;
f.next = g;
}
@Test
public void testRoot() {
testContent("ROOT", Storage.getRoot(), "AD");
}
@Test
public void testInitialHeap() {
testContent("YOUNG HEAP1", Storage.getYoungHeap(), "ABCDEFG");
testContent("OLD HEAP1", Storage.getOldHeap(), ""); }
@Test
public void testAfterFirstGC() {
Storage.gc();
Storage.getYoungHeap();
Storage.getOldHeap();
testContent("YOUNG HEAP2", Storage.getYoungHeap(), "");
testContent("OLD HEAP2", Storage.getOldHeap(), "ABCDEFG");
}
@Test
public void testAfterFirstChangeGC() {
Storage.gc();
e.next = d;
Storage.gc();
testContent("YOUNG HEAP3", Storage.getYoungHeap(), "");
testContent("OLD HEAP3", Storage.getOldHeap(), "ABCDE");
}
@Test
public void testAfterSecondChangeGC() {
Storage.gc();
e.next = d;
Storage.gc();
a.next = null;
Storage.gc();
testContent("YOUNG HEAP4", Storage.getYoungHeap(), "");
testContent("OLD HEAP4", Storage.getOldHeap(), "ABCDE");
}
@Test
public void testAfterSecondCallGC() {
Storage.gc();
e.next = d;
Storage.gc();
a.next = null;
Storage.gc();
Storage.gc();
testContent("YOUNG HEAP5", Storage.getYoungHeap(), "");
testContent("OLD HEAP5", Storage.getOldHeap(), "ADE");
}
@Test
public void testAfterAddObjecthGC() {
Storage.gc();
e.next = d;
Storage.gc();
a.next = null;
Storage.gc();
Storage.gc();
h = new_CObject("H");
a.next = h;
testContent("YOUNG HEAP5", Storage.getYoungHeap(), "H");
testContent("OLD HEAP5", Storage.getOldHeap(), "ADE");
}
@Test
public void testFinalHeap() {
Storage.gc();
e.next = d;
Storage.gc();
a.next = null;
Storage.gc();
Storage.gc();
h = new_CObject("H");
a.next = h;
testContent("YOUNG HEAP5", Storage.getYoungHeap(), "H");
testContent("OLD HEAP5", Storage.getOldHeap(), "ADE");
Storage.gc();
testContent("YOUNG HEAP5", Storage.getYoungHeap(), "");
testContent("OLD HEAP5", Storage.getOldHeap(), "ADEH");
}
}