mirror of https://github.com/alibaba/arthas.git
Merge tag 'arthas-all-3.5.6' into channel-server
commit
6a8c7acd11
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,25 @@
|
||||
package com.taobao.arthas.core.command.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Model of 'memory' command
|
||||
* @author hengyunabc 2022-03-01
|
||||
*/
|
||||
public class MemoryModel extends ResultModel {
|
||||
private Map<String, List<MemoryEntryVO>> memoryInfo;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "memory";
|
||||
}
|
||||
|
||||
public Map<String, List<MemoryEntryVO>> getMemoryInfo() {
|
||||
return memoryInfo;
|
||||
}
|
||||
|
||||
public void setMemoryInfo(Map<String, List<MemoryEntryVO>> memoryInfo) {
|
||||
this.memoryInfo = memoryInfo;
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package com.taobao.arthas.core.command.monitor200;
|
||||
|
||||
import static com.taobao.arthas.core.command.model.MemoryEntryVO.TYPE_BUFFER_POOL;
|
||||
import static com.taobao.arthas.core.command.model.MemoryEntryVO.TYPE_HEAP;
|
||||
import static com.taobao.arthas.core.command.model.MemoryEntryVO.TYPE_NON_HEAP;
|
||||
|
||||
import java.lang.management.BufferPoolMXBean;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
import java.lang.management.MemoryType;
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.taobao.arthas.core.command.Constants;
|
||||
import com.taobao.arthas.core.command.model.MemoryEntryVO;
|
||||
import com.taobao.arthas.core.command.model.MemoryModel;
|
||||
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
|
||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||
import com.taobao.arthas.core.util.StringUtils;
|
||||
import com.taobao.middleware.cli.annotations.Description;
|
||||
import com.taobao.middleware.cli.annotations.Name;
|
||||
import com.taobao.middleware.cli.annotations.Summary;
|
||||
|
||||
/**
|
||||
* @author hengyunabc 2022-03-01
|
||||
*/
|
||||
@Name("memory")
|
||||
@Summary("Display jvm memory info.")
|
||||
@Description(Constants.EXAMPLE + " memory\n" + Constants.WIKI + Constants.WIKI_HOME + "memory")
|
||||
public class MemoryCommand extends AnnotatedCommand {
|
||||
@Override
|
||||
public void process(CommandProcess process) {
|
||||
MemoryModel result = new MemoryModel();
|
||||
result.setMemoryInfo(memoryInfo());
|
||||
process.appendResult(result);
|
||||
process.end();
|
||||
}
|
||||
|
||||
static Map<String, List<MemoryEntryVO>> memoryInfo() {
|
||||
List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
|
||||
Map<String, List<MemoryEntryVO>> memoryInfoMap = new LinkedHashMap<String, List<MemoryEntryVO>>();
|
||||
|
||||
// heap
|
||||
MemoryUsage heapMemoryUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
|
||||
List<MemoryEntryVO> heapMemEntries = new ArrayList<MemoryEntryVO>();
|
||||
heapMemEntries.add(createMemoryEntryVO(TYPE_HEAP, TYPE_HEAP, heapMemoryUsage));
|
||||
for (MemoryPoolMXBean poolMXBean : memoryPoolMXBeans) {
|
||||
if (MemoryType.HEAP.equals(poolMXBean.getType())) {
|
||||
MemoryUsage usage = getUsage(poolMXBean);
|
||||
if (usage != null) {
|
||||
String poolName = StringUtils.beautifyName(poolMXBean.getName());
|
||||
heapMemEntries.add(createMemoryEntryVO(TYPE_HEAP, poolName, usage));
|
||||
}
|
||||
}
|
||||
}
|
||||
memoryInfoMap.put(TYPE_HEAP, heapMemEntries);
|
||||
|
||||
// non-heap
|
||||
MemoryUsage nonHeapMemoryUsage = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
|
||||
List<MemoryEntryVO> nonheapMemEntries = new ArrayList<MemoryEntryVO>();
|
||||
nonheapMemEntries.add(createMemoryEntryVO(TYPE_NON_HEAP, TYPE_NON_HEAP, nonHeapMemoryUsage));
|
||||
for (MemoryPoolMXBean poolMXBean : memoryPoolMXBeans) {
|
||||
if (MemoryType.NON_HEAP.equals(poolMXBean.getType())) {
|
||||
MemoryUsage usage = getUsage(poolMXBean);
|
||||
if (usage != null) {
|
||||
String poolName = StringUtils.beautifyName(poolMXBean.getName());
|
||||
nonheapMemEntries.add(createMemoryEntryVO(TYPE_NON_HEAP, poolName, usage));
|
||||
}
|
||||
}
|
||||
}
|
||||
memoryInfoMap.put(TYPE_NON_HEAP, nonheapMemEntries);
|
||||
|
||||
addBufferPoolMemoryInfo(memoryInfoMap);
|
||||
return memoryInfoMap;
|
||||
}
|
||||
|
||||
private static MemoryUsage getUsage(MemoryPoolMXBean memoryPoolMXBean) {
|
||||
try {
|
||||
return memoryPoolMXBean.getUsage();
|
||||
} catch (InternalError e) {
|
||||
// Defensive for potential InternalError with some specific JVM options. Based on its Javadoc,
|
||||
// MemoryPoolMXBean.getUsage() should return null, not throwing InternalError, so it seems to be a JVM bug.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void addBufferPoolMemoryInfo(Map<String, List<MemoryEntryVO>> memoryInfoMap) {
|
||||
try {
|
||||
List<MemoryEntryVO> bufferPoolMemEntries = new ArrayList<MemoryEntryVO>();
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class bufferPoolMXBeanClass = Class.forName("java.lang.management.BufferPoolMXBean");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<BufferPoolMXBean> bufferPoolMXBeans = ManagementFactory.getPlatformMXBeans(bufferPoolMXBeanClass);
|
||||
for (BufferPoolMXBean mbean : bufferPoolMXBeans) {
|
||||
long used = mbean.getMemoryUsed();
|
||||
long total = mbean.getTotalCapacity();
|
||||
bufferPoolMemEntries
|
||||
.add(new MemoryEntryVO(TYPE_BUFFER_POOL, mbean.getName(), used, total, Long.MIN_VALUE));
|
||||
}
|
||||
memoryInfoMap.put(TYPE_BUFFER_POOL, bufferPoolMemEntries);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static MemoryEntryVO createMemoryEntryVO(String type, String name, MemoryUsage memoryUsage) {
|
||||
return new MemoryEntryVO(type, name, memoryUsage.getUsed(), memoryUsage.getCommitted(), memoryUsage.getMax());
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
package com.taobao.arthas.core.command.view;
|
||||
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.taobao.arthas.core.command.model.MemoryEntryVO;
|
||||
import com.taobao.arthas.core.command.model.MemoryModel;
|
||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||
import com.taobao.text.Color;
|
||||
import com.taobao.text.Decoration;
|
||||
import com.taobao.text.Style;
|
||||
import com.taobao.text.ui.RowElement;
|
||||
import com.taobao.text.ui.TableElement;
|
||||
import com.taobao.text.util.RenderUtil;
|
||||
|
||||
/**
|
||||
* View of 'memory' command
|
||||
*
|
||||
* @author hengyunabc 2022-03-01
|
||||
*/
|
||||
public class MemoryView extends ResultView<MemoryModel> {
|
||||
|
||||
@Override
|
||||
public void draw(CommandProcess process, MemoryModel result) {
|
||||
TableElement table = drawMemoryInfo(result.getMemoryInfo());
|
||||
process.write(RenderUtil.render(table, process.width()));
|
||||
}
|
||||
|
||||
static TableElement drawMemoryInfo(Map<String, List<MemoryEntryVO>> memoryInfo) {
|
||||
TableElement table = new TableElement(3, 1, 1, 1, 1).rightCellPadding(1);
|
||||
table.add(new RowElement().style(Decoration.bold.fg(Color.black).bg(Color.white)).add("Memory",
|
||||
"used", "total", "max", "usage"));
|
||||
List<MemoryEntryVO> heapMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_HEAP);
|
||||
//heap memory
|
||||
for (MemoryEntryVO memoryEntryVO : heapMemoryEntries) {
|
||||
if (MemoryEntryVO.TYPE_HEAP.equals(memoryEntryVO.getName())) {
|
||||
new MemoryEntry(memoryEntryVO).addTableRow(table, Decoration.bold.bold());
|
||||
} else {
|
||||
new MemoryEntry(memoryEntryVO).addTableRow(table);
|
||||
}
|
||||
}
|
||||
|
||||
//non-heap memory
|
||||
List<MemoryEntryVO> nonheapMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_NON_HEAP);
|
||||
for (MemoryEntryVO memoryEntryVO : nonheapMemoryEntries) {
|
||||
if (MemoryEntryVO.TYPE_NON_HEAP.equals(memoryEntryVO.getName())) {
|
||||
new MemoryEntry(memoryEntryVO).addTableRow(table, Decoration.bold.bold());
|
||||
} else {
|
||||
new MemoryEntry(memoryEntryVO).addTableRow(table);
|
||||
}
|
||||
}
|
||||
|
||||
//buffer-pool
|
||||
List<MemoryEntryVO> bufferPoolMemoryEntries = memoryInfo.get(MemoryEntryVO.TYPE_BUFFER_POOL);
|
||||
if (bufferPoolMemoryEntries != null) {
|
||||
for (MemoryEntryVO memoryEntryVO : bufferPoolMemoryEntries) {
|
||||
new MemoryEntry(memoryEntryVO).addTableRow(table);
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
static class MemoryEntry {
|
||||
String name;
|
||||
long used;
|
||||
long total;
|
||||
long max;
|
||||
|
||||
int unit;
|
||||
String unitStr;
|
||||
|
||||
public MemoryEntry(String name, long used, long total, long max) {
|
||||
this.name = name;
|
||||
this.used = used;
|
||||
this.total = total;
|
||||
this.max = max;
|
||||
|
||||
unitStr = "K";
|
||||
unit = 1024;
|
||||
if (used / 1024 / 1024 > 0) {
|
||||
unitStr = "M";
|
||||
unit = 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
public MemoryEntry(String name, MemoryUsage usage) {
|
||||
this(name, usage.getUsed(), usage.getCommitted(), usage.getMax());
|
||||
}
|
||||
|
||||
public MemoryEntry(MemoryEntryVO memoryEntryVO) {
|
||||
this(memoryEntryVO.getName(), memoryEntryVO.getUsed(), memoryEntryVO.getTotal(), memoryEntryVO.getMax());
|
||||
}
|
||||
|
||||
private String format(long value) {
|
||||
String valueStr = "-";
|
||||
if (value == -1) {
|
||||
return "-1";
|
||||
}
|
||||
if (value != Long.MIN_VALUE) {
|
||||
valueStr = value / unit + unitStr;
|
||||
}
|
||||
return valueStr;
|
||||
}
|
||||
|
||||
public void addTableRow(TableElement table) {
|
||||
double usage = used / (double) (max == -1 || max == Long.MIN_VALUE ? total : max) * 100;
|
||||
if (Double.isNaN(usage) || Double.isInfinite(usage)) {
|
||||
usage = 0;
|
||||
}
|
||||
table.row(name, format(used), format(total), format(max), String.format("%.2f%%", usage));
|
||||
}
|
||||
|
||||
public void addTableRow(TableElement table, Style.Composite style) {
|
||||
double usage = used / (double) (max == -1 || max == Long.MIN_VALUE ? total : max) * 100;
|
||||
if (Double.isNaN(usage) || Double.isInfinite(usage)) {
|
||||
usage = 0;
|
||||
}
|
||||
table.add(new RowElement().style(style).add(name, format(used), format(total), format(max),
|
||||
String.format("%.2f%%", usage)));
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue