diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelAdviceListener.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelAdviceListener.java index 09bc7c3ed..9566a3ddf 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelAdviceListener.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelAdviceListener.java @@ -1,28 +1,36 @@ package com.taobao.arthas.core.command.monitor200; -import com.taobao.arthas.core.advisor.ReflectAdviceListenerAdapter; -import com.taobao.arthas.core.command.express.ExpressException; -import com.taobao.arthas.core.shell.command.CommandProcess; -import com.alibaba.arthas.deps.org.slf4j.Logger; -import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; -import com.taobao.arthas.core.advisor.Advice; -import com.taobao.arthas.core.advisor.ArthasMethod; -import com.taobao.arthas.core.util.LogUtil; -import com.taobao.arthas.core.util.ThreadLocalWatch; -import com.taobao.text.ui.TableElement; -import com.taobao.text.util.RenderUtil; - -import java.util.Date; - import static com.taobao.arthas.core.command.monitor200.TimeTunnelTable.createTable; import static com.taobao.arthas.core.command.monitor200.TimeTunnelTable.fillTableHeader; import static com.taobao.arthas.core.command.monitor200.TimeTunnelTable.fillTableRow; +import java.util.Date; + +import com.alibaba.arthas.deps.org.slf4j.Logger; +import com.alibaba.arthas.deps.org.slf4j.LoggerFactory; +import com.taobao.arthas.core.advisor.Advice; +import com.taobao.arthas.core.advisor.ArthasMethod; +import com.taobao.arthas.core.advisor.AdviceListenerAdapter; +import com.taobao.arthas.core.command.express.ExpressException; +import com.taobao.arthas.core.shell.command.CommandProcess; +import com.taobao.arthas.core.util.LogUtil; +import com.taobao.arthas.core.util.ThreadLocalWatch; +import com.taobao.text.ui.TableElement; +import com.taobao.text.util.RenderUtil; + /** * @author beiwei30 on 30/11/2016. + * @author hengyunabc 2020-05-20 */ -public class TimeTunnelAdviceListener extends ReflectAdviceListenerAdapter { +public class TimeTunnelAdviceListener extends AdviceListenerAdapter { private static final Logger logger = LoggerFactory.getLogger(TimeTunnelAdviceListener.class); + private final ThreadLocal argsRef = new ThreadLocal() { + @Override + protected ObjectStack initialValue() { + return new ObjectStack(512); + } + }; + private TimeTunnelCommand command; private CommandProcess process; @@ -40,18 +48,23 @@ public class TimeTunnelAdviceListener extends ReflectAdviceListenerAdapter { @Override public void before(ClassLoader loader, Class clazz, ArthasMethod method, Object target, Object[] args) throws Throwable { + argsRef.get().push(args); threadLocalWatch.start(); } @Override public void afterReturning(ClassLoader loader, Class clazz, ArthasMethod method, Object target, Object[] args, Object returnObject) throws Throwable { + //取出入参时的 args,因为在函数执行过程中 args可能被修改 + args = (Object[]) argsRef.get().pop(); afterFinishing(Advice.newForAfterRetuning(loader, clazz, method, target, args, returnObject)); } @Override public void afterThrowing(ClassLoader loader, Class clazz, ArthasMethod method, Object target, Object[] args, Throwable throwable) { + //取出入参时的 args,因为在函数执行过程中 args可能被修改 + args = (Object[]) argsRef.get().pop(); afterFinishing(Advice.newForAfterThrowing(loader, clazz, method, target, args, throwable)); } @@ -93,4 +106,53 @@ public class TimeTunnelAdviceListener extends ReflectAdviceListenerAdapter { abortProcess(process, command.getNumberOfLimit()); } } + + /** + * + *
+     * 一个特殊的stack,为了追求效率,避免扩容。
+     * 因为这个stack的push/pop 并不一定成对调用,比如可能push执行了,但是后面的流程被中断了,pop没有被执行。
+     * 如果不固定大小,一直增长的话,极端情况下可能应用有内存问题。
+     * 如果到达容量,pos会重置,循环存储数据。所以使用这个Stack如果在极端情况下统计的数据会不准确,只用于monitor/watch等命令的计时。
+     * 
+     * 
+ * + * @author hengyunabc 2019-11-20 + * + */ + static class ObjectStack { + private Object[] array; + private int pos = 0; + private int cap; + + public ObjectStack(int maxSize) { + array = new Object[maxSize]; + cap = array.length; + } + + public int size() { + return pos; + } + + public void push(Object value) { + if (pos < cap) { + array[pos++] = value; + } else { + // if array is full, reset pos + pos = 0; + array[pos++] = value; + } + } + + public Object pop() { + if (pos > 0) { + pos--; + return array[pos]; + } else { + pos = cap; + pos--; + return array[pos]; + } + } + } }