From 1ad02b1a3e81e932116e714fa59a4d6bad5fa4e7 Mon Sep 17 00:00:00 2001 From: Victoria Sinelnikova Date: Sun, 27 Oct 2019 15:48:53 +0300 Subject: [PATCH 1/2] Homework 4: automatic logging (proxy) --- hw04-logging/README.md | 22 +++++ hw04-logging/pom.xml | 64 +++++++++++++ .../java/ru/otus/homework/annotation/Log.java | 11 +++ .../main/java/ru/otus/homework/asm/Agent.java | 49 ++++++++++ .../ru/otus/homework/asm/LogClassVisitor.java | 21 +++++ .../otus/homework/asm/LogMethodVisitor.java | 93 +++++++++++++++++++ .../java/ru/otus/homework/asm/Logger.java | 22 +++++ .../java/ru/otus/homework/demo/AsmDemo.java | 21 +++++ .../ru/otus/homework/demo/TestLogging.java | 49 ++++++++++ .../ru/otus/homework/demo/TestObject.java | 19 ++++ pom.xml | 1 + 11 files changed, 372 insertions(+) create mode 100644 hw04-logging/README.md create mode 100644 hw04-logging/pom.xml create mode 100644 hw04-logging/src/main/java/ru/otus/homework/annotation/Log.java create mode 100644 hw04-logging/src/main/java/ru/otus/homework/asm/Agent.java create mode 100755 hw04-logging/src/main/java/ru/otus/homework/asm/LogClassVisitor.java create mode 100755 hw04-logging/src/main/java/ru/otus/homework/asm/LogMethodVisitor.java create mode 100755 hw04-logging/src/main/java/ru/otus/homework/asm/Logger.java create mode 100755 hw04-logging/src/main/java/ru/otus/homework/demo/AsmDemo.java create mode 100755 hw04-logging/src/main/java/ru/otus/homework/demo/TestLogging.java create mode 100644 hw04-logging/src/main/java/ru/otus/homework/demo/TestObject.java diff --git a/hw04-logging/README.md b/hw04-logging/README.md new file mode 100644 index 0000000..d9dc649 --- /dev/null +++ b/hw04-logging/README.md @@ -0,0 +1,22 @@ +# Автомагическое логирование. + Разработайте такой функционал: + метод класса можно пометить самодельной аннотацией @Log, например, так: + + class TestLogging { + @Log + public void calculation(int param) {}; + } + + При вызове этого метода "автомагически" в консоль должны логироваться + значения параметров. Например так. + + class Demo { + public void action() { + new TestLogging().calculation(6); + } + } + + В консоли дожно быть: + executed method: calculation, param: 6 + + Обратите внимание: явного вызова логирования быть не должно. \ No newline at end of file diff --git a/hw04-logging/pom.xml b/hw04-logging/pom.xml new file mode 100644 index 0000000..8657a35 --- /dev/null +++ b/hw04-logging/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + + ru.otus + otus-java + 2019-09-SNAPSHOT + + + hw04-logging + hw04-logging + + + 7.2 + 3.2.1 + + + + + org.ow2.asm + asm + ${asm.version} + + + org.ow2.asm + asm-commons + ${asm.version} + + + + + + + maven-shade-plugin + ${maven-shade-plugin.version} + + + asmDemo + package + + shade + + + target/asmDemo.jar + + + + ru.otus.homework.demo.AsmDemo + ru.otus.homework.asm.Agent + + + + + + + + + + + diff --git a/hw04-logging/src/main/java/ru/otus/homework/annotation/Log.java b/hw04-logging/src/main/java/ru/otus/homework/annotation/Log.java new file mode 100644 index 0000000..2b490d0 --- /dev/null +++ b/hw04-logging/src/main/java/ru/otus/homework/annotation/Log.java @@ -0,0 +1,11 @@ +package ru.otus.homework.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Log { +} diff --git a/hw04-logging/src/main/java/ru/otus/homework/asm/Agent.java b/hw04-logging/src/main/java/ru/otus/homework/asm/Agent.java new file mode 100644 index 0000000..c0c96f8 --- /dev/null +++ b/hw04-logging/src/main/java/ru/otus/homework/asm/Agent.java @@ -0,0 +1,49 @@ +package ru.otus.homework.asm; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; + +public class Agent { + private static final String OUTPUT_FILE = "proxyASM.class"; + + public static void premain(String agentArgs, Instrumentation inst) { + + inst.addTransformer(new ClassFileTransformer() { + @Override + public byte[] transform(ClassLoader loader, String className, + Class classBeingRedefined, + ProtectionDomain protectionDomain, + byte[] classfileBuffer) { + if (className.equals(agentArgs)) { + return scanLogAnnotation(classfileBuffer); + } + return classfileBuffer; + } + }); + } + + private static byte[] scanLogAnnotation(byte[] classfileBuffer) { + ClassReader reader = new ClassReader(classfileBuffer); + ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS); + ClassVisitor visitor = new LogClassVisitor(writer); + reader.accept(visitor, Opcodes.ASM5); + + byte[] finalClass = writer.toByteArray(); + + try (OutputStream fos = new FileOutputStream(OUTPUT_FILE)) { + fos.write(finalClass); + } catch (IOException e) { + e.printStackTrace(); + } + return finalClass; + } +} diff --git a/hw04-logging/src/main/java/ru/otus/homework/asm/LogClassVisitor.java b/hw04-logging/src/main/java/ru/otus/homework/asm/LogClassVisitor.java new file mode 100755 index 0000000..12fb5ec --- /dev/null +++ b/hw04-logging/src/main/java/ru/otus/homework/asm/LogClassVisitor.java @@ -0,0 +1,21 @@ +package ru.otus.homework.asm; + +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class LogClassVisitor extends ClassVisitor implements Opcodes { + + public LogClassVisitor(ClassVisitor writer) { + super(ASM5, writer); + } + + @Override + public MethodVisitor visitMethod(int access, String methodName, String desc, + String signature, String[] exceptions) { + + MethodVisitor methodVisitor = cv.visitMethod(access, methodName, desc, signature, + exceptions); + return new LogMethodVisitor(methodVisitor, methodName, desc, access); + } +} diff --git a/hw04-logging/src/main/java/ru/otus/homework/asm/LogMethodVisitor.java b/hw04-logging/src/main/java/ru/otus/homework/asm/LogMethodVisitor.java new file mode 100755 index 0000000..8a3398f --- /dev/null +++ b/hw04-logging/src/main/java/ru/otus/homework/asm/LogMethodVisitor.java @@ -0,0 +1,93 @@ +package ru.otus.homework.asm; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +/** + * Add logging if method has @Log annotation + */ +public class LogMethodVisitor extends MethodVisitor implements Opcodes { + private static final String LOG_ANNOTATION = "Lru/otus/homework/annotation/Log;"; + + private final String methodName; + private final String descriptor; + private final int access; + private boolean isAnnotationPresent; + + public LogMethodVisitor(MethodVisitor methodVisitor, String methodName, String descriptor, int access) { + super(ASM5, methodVisitor); + this.methodName = methodName; + this.descriptor = descriptor; + this.access = access; + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + if (LOG_ANNOTATION.equals(desc)) { + isAnnotationPresent = true; + } + return super.visitAnnotation(desc, visible); + } + + @Override + public void visitCode() { + if (isAnnotationPresent) { + Type[] argTypes = Type.getArgumentTypes(descriptor); + int i = (access | ACC_STATIC) == 0 ? 0 : 1; + int index = argTypes.length + i; + + mv.visitIntInsn(BIPUSH, argTypes.length); + mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); + + int x = 0; + for (Type t : argTypes) { + mv.visitInsn(DUP); + mv.visitIntInsn(BIPUSH, x); + if (t.equals(Type.BOOLEAN_TYPE)) { + mv.visitVarInsn(ILOAD, i); + invokeStatic("java/lang/Boolean", "(Z)Ljava/lang/Boolean;"); + } else if (t.equals(Type.BYTE_TYPE)) { + mv.visitVarInsn(ILOAD, i); + invokeStatic("java/lang/Byte", "(B)Ljava/lang/Byte;"); + } else if (t.equals(Type.CHAR_TYPE)) { + mv.visitVarInsn(ILOAD, i); + invokeStatic("java/lang/Character", "(C)Ljava/lang/Character;"); + } else if (t.equals(Type.SHORT_TYPE)) { + mv.visitVarInsn(ILOAD, i); + invokeStatic("java/lang/Short", "(S)Ljava/lang/Short;"); + } else if (t.equals(Type.INT_TYPE)) { + mv.visitVarInsn(ILOAD, i); + invokeStatic("java/lang/Integer", "(I)Ljava/lang/Integer;"); + } else if (t.equals(Type.LONG_TYPE)) { + mv.visitVarInsn(LLOAD, i); + invokeStatic("java/lang/Long", "(J)Ljava/lang/Long;"); + i++; + } else if (t.equals(Type.FLOAT_TYPE)) { + mv.visitVarInsn(FLOAD, i); + invokeStatic("java/lang/Float", "(F)Ljava/lang/Float;"); + } else if (t.equals(Type.DOUBLE_TYPE)) { + mv.visitVarInsn(DLOAD, i); + invokeStatic("java/lang/Double", "(D)Ljava/lang/Double;"); + i++; + } else { + mv.visitVarInsn(ALOAD, i); + } + mv.visitInsn(AASTORE); + i++; + x++; + } + mv.visitVarInsn(ASTORE, index); + this.visitLdcInsn(methodName); + this.visitVarInsn(ALOAD, index); + mv.visitMethodInsn(INVOKESTATIC, "ru/otus/homework/asm/Logger", "logMethod", + "(Ljava/lang/String;[Ljava/lang/Object;)V", false); + } + super.visitCode(); + } + + private void invokeStatic(String owner, String descriptor) { + mv.visitMethodInsn(INVOKESTATIC, owner, "valueOf", descriptor, false); + } +} diff --git a/hw04-logging/src/main/java/ru/otus/homework/asm/Logger.java b/hw04-logging/src/main/java/ru/otus/homework/asm/Logger.java new file mode 100755 index 0000000..5cfc943 --- /dev/null +++ b/hw04-logging/src/main/java/ru/otus/homework/asm/Logger.java @@ -0,0 +1,22 @@ +package ru.otus.homework.asm; + +import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * This class is called by LogMethodVisitor to log method`s name and arguments + */ +public class Logger { + + public static void logMethod(String methodName, Object[] args) { + String log = String.format("executed method %s", methodName); + if (args.length > 0) { + String params = Arrays.stream(args). + filter(Objects::nonNull). + map(Object::toString).collect(Collectors.joining(", ")); + log = log.concat(", params: ").concat(params); + } + System.out.println(log); + } +} diff --git a/hw04-logging/src/main/java/ru/otus/homework/demo/AsmDemo.java b/hw04-logging/src/main/java/ru/otus/homework/demo/AsmDemo.java new file mode 100755 index 0000000..eff8dc9 --- /dev/null +++ b/hw04-logging/src/main/java/ru/otus/homework/demo/AsmDemo.java @@ -0,0 +1,21 @@ +package ru.otus.homework.demo; + +/* + * Class with methods which has @Log annotation should be passed as argument for javaagent: + * + * java -javaagent:target/asmDemo.jar=ru/otus/homework/demo/TestLogging -jar target/asmDemo.jar + */ +public class AsmDemo { + + public static void main(String[] args) { + TestLogging testLogging = new TestLogging(); + testLogging.testNoArgs(); + testLogging.testNoLog(); + testLogging.testObject(new TestObject("string", 357)); + testLogging.testInt(3, 2, 1); + testLogging.testIntegerFloatDouble(1, 2.1f, 3.111111); + testLogging.testBooleanShortByte(true, (short) 1, (byte) 1); + testLogging.testLongDouble(5L, 7.8); + testLogging.testStringChar("asdfg", 't'); + } +} diff --git a/hw04-logging/src/main/java/ru/otus/homework/demo/TestLogging.java b/hw04-logging/src/main/java/ru/otus/homework/demo/TestLogging.java new file mode 100755 index 0000000..d4bb803 --- /dev/null +++ b/hw04-logging/src/main/java/ru/otus/homework/demo/TestLogging.java @@ -0,0 +1,49 @@ +package ru.otus.homework.demo; + +import ru.otus.homework.annotation.Log; + +/** + * Test class + */ +public class TestLogging { + + @Log + public void testInt(int param1, int param2, int param3) { + System.out.println("Multiple int"); + } + + @Log + public void testIntegerFloatDouble(Integer i, Float f, Double d) { + System.out.println("Test integer, float"); + } + + @Log + public void testBooleanShortByte(boolean bool, short s, byte b) { + System.out.println("Test boolean, short, byte"); + } + + @Log + public void testLongDouble(long l, double d){ + System.out.println("Test long, double"); + } + + public void testNoLog() { + System.out.println("Log annotation is absent"); + } + + @Log + public void testNoArgs() { + System.out.println("No arguments"); + } + + @Log + public void testObject(TestObject o) { + System.out.println("Test object"); + } + + @Log + public String testStringChar(String s, char a) { + System.out.println("Test string and char"); + return s; + } +} diff --git a/hw04-logging/src/main/java/ru/otus/homework/demo/TestObject.java b/hw04-logging/src/main/java/ru/otus/homework/demo/TestObject.java new file mode 100644 index 0000000..83a1afd --- /dev/null +++ b/hw04-logging/src/main/java/ru/otus/homework/demo/TestObject.java @@ -0,0 +1,19 @@ +package ru.otus.homework.demo; + +public class TestObject { + private String s; + private int i; + + public TestObject(String s, int i) { + this.s = s; + this.i = i; + } + + @Override + public String toString() { + return "TestObject{" + + "s='" + s + '\'' + + ", i=" + i + + '}'; + } +} diff --git a/pom.xml b/pom.xml index 990ec7c..73b4c7a 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ hw01-maven hw02-arrayList + hw04-logging hw05-testFramework hw06-atm hw07-atm-department From 425f1764bed14321aa24acfadae19781641f0a94 Mon Sep 17 00:00:00 2001 From: Victoria Date: Sun, 28 Jun 2020 21:07:11 +0300 Subject: [PATCH 2/2] Homework 03: garbage collector --- .gitignore | 3 +- hw03-gc/Conclusions.md | 52 ++++++++++++++ hw03-gc/README.md | 19 +++++ hw03-gc/pom.xml | 38 ++++++++++ .../main/java/ru/otus/homework/GcDemo.java | 72 +++++++++++++++++++ .../java/ru/otus/homework/GcStatistic.java | 62 ++++++++++++++++ .../java/ru/otus/homework/MemoryLeakApp.java | 24 +++++++ hw03-gc/src/main/resources/example.txt | 7 ++ hw03-gc/src/main/resources/logback.xml | 13 ++++ 9 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 hw03-gc/Conclusions.md create mode 100644 hw03-gc/README.md create mode 100644 hw03-gc/pom.xml create mode 100644 hw03-gc/src/main/java/ru/otus/homework/GcDemo.java create mode 100644 hw03-gc/src/main/java/ru/otus/homework/GcStatistic.java create mode 100644 hw03-gc/src/main/java/ru/otus/homework/MemoryLeakApp.java create mode 100644 hw03-gc/src/main/resources/example.txt create mode 100644 hw03-gc/src/main/resources/logback.xml diff --git a/.gitignore b/.gitignore index b6065fb..b8174c2 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ hs_err_pid* *.iml .idea -target \ No newline at end of file +target +logs diff --git a/hw03-gc/Conclusions.md b/hw03-gc/Conclusions.md new file mode 100644 index 0000000..6bfba4c --- /dev/null +++ b/hw03-gc/Conclusions.md @@ -0,0 +1,52 @@ +# +**Статистика работы сборщиков мусора (java-11-openjdk)** + +Имя | Событие | Длительность,мс +--- | :---: | :---: +|**Serial**| +Copy | 4 | 474 | +MarkSweepCompact | 1 | 675 +|**Parallel**| +PS Scavenge | 3 | 195 +PS MarkSweep | 5 | 4496 +|**CMS**| +ParNew | 4 | 547 +ConcurrentMarkSweep | 40 | 155899 +|**G1**| +G1 Young Generation | 16 | 223 +G1 Old Generation | 1 | 296 + +**Статистика работы сборщиков мусора (java-14-oracle)** + +Имя | Событие | Длительность,мс +--- | :---: | :---: +|**Serial**| +Copy | 4 | 429 | +MarkSweepCompact | 1 | 461 +|**Parallel**| +PS Scavenge | 3 | 203 +PS MarkSweep | 3 | 2100 +|**G1**| +G1 Young Generation | 16 | 264 +G1 Old Generation | 1 | 314 + +**Время работы приложения при использовании разных сборщиков мусора и jdk** + +Сборщик мусора|Время работы приложения (java-11-openjdk), с |Время работы приложения (java-14-oracle), с +---| :---:| :---: +Serial | 281 | 370 +Parallel | 314 | 337 +CMS | 342 | - +G1 | 397 | 383 + + **Выводы:** + + - Для написанного приложения лучше всего показал себя G1 сборщик мусора. С G1 приложение работало + дольше, общая длительность пауз была меньше, чем с Serial, Parallel, CMS сборщиками; + - Минорные сборки G1 начинались раньше (при размере heap 20Mb, тогда как для других GC первые + сборки стартовали при размере heap больше 100Mb), выполнялись чаще (G1 имеет максимальное число + минорных сборок из рассмотренных сборщиков мусора) и были короткими (время на одну минорную сборку + минимально у G1, общая длительность минорных сборок меньше, чем у Serial и CMS сборщиков); + - Эффективность Parallel и CMS сборщиков мусора оказалась наименьшей: полных сборок мусора было больше, + приложение останавливалось чаще, время, затраченное на сборку мусора, значительно превышало аналогичное + значение для Serial и G1 сборщиков. diff --git a/hw03-gc/README.md b/hw03-gc/README.md new file mode 100644 index 0000000..5f638fd --- /dev/null +++ b/hw03-gc/README.md @@ -0,0 +1,19 @@ +# Сравнение разных сборщиков мусора + Написать приложение, которое следит за сборками мусора и пишет в лог количество сборок каждого типа + (young, old) и время которое ушло на сборки в минуту. + + Добиться OutOfMemory в этом приложении через медленное подтекание по памяти + (например добавлять элементы в List и удалять только половину). + + Настроить приложение (можно добавлять Thread.sleep(...)) так чтобы оно падало + с OOM примерно через 5 минут после начала работы. + + Собрать статистику (количество сборок, время на сборки) по разным GC. + + !!! Сделать выводы !!! + ЭТО САМАЯ ВАЖНАЯ ЧАСТЬ РАБОТЫ: + Какой gc лучше и почему? + + Выводы оформить в файле Сonclusions.md в корне папки проекта. + Результаты измерений сведите в таблицу. + \ No newline at end of file diff --git a/hw03-gc/pom.xml b/hw03-gc/pom.xml new file mode 100644 index 0000000..9ee3b5e --- /dev/null +++ b/hw03-gc/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + + ru.otus + otus-java + 2019-09-SNAPSHOT + + + hw03-gc + jar + hw03-gc + + + 11 + 11 + + + + + ch.qos.logback + logback-classic + + + + + ${project.name} + + + org.apache.maven.plugins + maven-assembly-plugin + + + + diff --git a/hw03-gc/src/main/java/ru/otus/homework/GcDemo.java b/hw03-gc/src/main/java/ru/otus/homework/GcDemo.java new file mode 100644 index 0000000..1ddcdab --- /dev/null +++ b/hw03-gc/src/main/java/ru/otus/homework/GcDemo.java @@ -0,0 +1,72 @@ +package ru.otus.homework; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * -Xms512m + * -Xmx512m + * -Xlog:gc=debug:file=./logs/gc.log:tags,uptime,time,level:filecount=10,filesize=10m + * -XX:+HeapDumpOnOutOfMemoryError + * -XX:HeapDumpPath=./logs/dump + * -XX:+UseG1GC + *

+ * -XX:+UseSerialGC + * -XX:+UseParallelGC + * -XX:+UseConcMarkSweepGC + * -XX:+UseG1GC + */ +public class GcDemo { + private static final Logger LOG = LoggerFactory.getLogger(GcDemo.class); + + public static void main(String[] args) { + new GcDemo().startDemo(); + } + + private void startDemo() { + Map> map = new HashMap<>(); + GcStatistic gcStatistic = new GcStatistic(map); + gcStatistic.switchOnMonitoring(); + + long beginTime = System.currentTimeMillis(); + List list = readFile(); + + MemoryLeakApp appDemo = new MemoryLeakApp(list); + try { + appDemo.run(); + } catch (OutOfMemoryError e) { + LOG.info("time: {}", (System.currentTimeMillis() - beginTime) / 1000); + LOG.info("GC statistic: {}", map); + LOG.info("Out of memory error", e); + } + } + + private List readFile() { + List list = new ArrayList<>(); + try { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream in = classLoader.getResourceAsStream("example.txt"); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { + String line; + while ((line = reader.readLine()) != null) { + String[] ar = line.split(" "); + list.addAll(Arrays.asList(ar)); + } + } + } catch (IOException e) { + LOG.error("Can not read file ", e); + } + return list; + } +} diff --git a/hw03-gc/src/main/java/ru/otus/homework/GcStatistic.java b/hw03-gc/src/main/java/ru/otus/homework/GcStatistic.java new file mode 100644 index 0000000..d780d2d --- /dev/null +++ b/hw03-gc/src/main/java/ru/otus/homework/GcStatistic.java @@ -0,0 +1,62 @@ +package ru.otus.homework; + +import com.sun.management.GarbageCollectionNotificationInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import javax.management.openmbean.CompositeData; +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class GcStatistic { + private static final Logger LOG = LoggerFactory.getLogger(GcStatistic.class); + private final Map> map; + + public GcStatistic(Map> map) { + this.map = map; + } + + public void switchOnMonitoring() { + List gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); + final MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); + for (GarbageCollectorMXBean gcbean : gcBeans) { + LOG.info("GC name: {}", gcbean.getName()); + NotificationEmitter emitter = (NotificationEmitter) gcbean; + NotificationListener listener = (Notification notification, Object handback) -> { + if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { + handleNotification(notification, + memoryMXBean.getHeapMemoryUsage().getUsed()); + } + }; + emitter.addNotificationListener(listener, null, null); + } + } + + private void handleNotification(Notification notification, long memoryUsed) { + GarbageCollectionNotificationInfo info = + GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData()); + String gcName = info.getGcName(); + long duration = info.getGcInfo().getDuration(); + + String heapMemory = String.format("%.2f Mb", (double)memoryUsed / 1_048_576); + LOG.info("Name: {}, action: {}, cause: {} ({} ms). Used heap memory {}", + info.getGcName(), info.getGcAction(), info.getGcCause(), duration, + heapMemory); + + if (map.containsKey(gcName)) { + Map actionStatistic = map.get(gcName); + long eventCount = actionStatistic.entrySet().iterator().next().getKey(); + long sumDuration = actionStatistic.get(eventCount) + duration; + map.put(gcName, Collections.singletonMap(eventCount + 1, sumDuration)); + } else { + map.put(gcName, Collections.singletonMap(1L, duration)); + } + } +} diff --git a/hw03-gc/src/main/java/ru/otus/homework/MemoryLeakApp.java b/hw03-gc/src/main/java/ru/otus/homework/MemoryLeakApp.java new file mode 100644 index 0000000..7f1a62b --- /dev/null +++ b/hw03-gc/src/main/java/ru/otus/homework/MemoryLeakApp.java @@ -0,0 +1,24 @@ +package ru.otus.homework; + +import java.util.ArrayList; +import java.util.List; + +public class MemoryLeakApp { + private static final List TEMP = new ArrayList<>(); + private static final int ITERATION = 100_000; + private final List init = new ArrayList<>(); + + public MemoryLeakApp(List in) { + init.addAll(in); + } + + public void run() { + for (int i = 0; i < ITERATION; i++) { + TEMP.addAll(init); + for (int j = 0; j < ITERATION / 2; j++) { + TEMP.add("empty" + i); + } + TEMP.removeAll(init); + } + } +} diff --git a/hw03-gc/src/main/resources/example.txt b/hw03-gc/src/main/resources/example.txt new file mode 100644 index 0000000..bd0602d --- /dev/null +++ b/hw03-gc/src/main/resources/example.txt @@ -0,0 +1,7 @@ +start:618 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(88 ms) start:779 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(114 ms) +start:939 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(85 ms) start:1076 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(53 ms) +start:1159 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(52 ms) start:1350 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(44 ms) +start:1414 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(37 ms) start:1476 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(69 ms) +start:1579 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(98 ms) start:1803 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Humongous Allocation(72 ms) +start:1935 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(154 ms) start:2141 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(108 ms) +start:2411 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(105 ms) start:2614 Name:G1 Young Generation, action:end of minor GC, gcCause:G1 Evacuation Pause(130 ms) diff --git a/hw03-gc/src/main/resources/logback.xml b/hw03-gc/src/main/resources/logback.xml new file mode 100644 index 0000000..08fc1ec --- /dev/null +++ b/hw03-gc/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + + %d{HH:mm:ss.SSS} - %msg%n + + + + + + +