专栏首页码匠的流水账聊聊springboot的HeapDumpWebEndpoint

聊聊springboot的HeapDumpWebEndpoint

本文主要研究下springboot的HeapDumpWebEndpoint

HeapDumpWebEndpointAutoConfiguration

spring-boot-actuator-autoconfigure-2.0.1.RELEASE-sources.jar!/org/springframework/boot/actuate/autoconfigure/management/HeapDumpWebEndpointAutoConfiguration.java

@Configuration
public class HeapDumpWebEndpointAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnEnabledEndpoint
    public HeapDumpWebEndpoint heapDumpWebEndpoint() {
        return new HeapDumpWebEndpoint();
    }

}

HeapDumpWebEndpoint

spring-boot-actuator-2.0.1.RELEASE-sources.jar!/org/springframework/boot/actuate/management/HeapDumpWebEndpoint.java

@WebEndpoint(id = "heapdump")
public class HeapDumpWebEndpoint {

    private final long timeout;

    private final Lock lock = new ReentrantLock();

    private HeapDumper heapDumper;

    public HeapDumpWebEndpoint() {
        this(TimeUnit.SECONDS.toMillis(10));
    }

    protected HeapDumpWebEndpoint(long timeout) {
        this.timeout = timeout;
    }

    @ReadOperation
    public WebEndpointResponse<Resource> heapDump(@Nullable Boolean live) {
        try {
            if (this.lock.tryLock(this.timeout, TimeUnit.MILLISECONDS)) {
                try {
                    return new WebEndpointResponse<>(
                            dumpHeap(live == null ? true : live));
                }
                finally {
                    this.lock.unlock();
                }
            }
        }
        catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
        catch (IOException ex) {
            return new WebEndpointResponse<>(
                    WebEndpointResponse.STATUS_INTERNAL_SERVER_ERROR);
        }
        catch (HeapDumperUnavailableException ex) {
            return new WebEndpointResponse<>(
                    WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);
        }
        return new WebEndpointResponse<>(WebEndpointResponse.STATUS_TOO_MANY_REQUESTS);
    }

    private Resource dumpHeap(boolean live) throws IOException, InterruptedException {
        if (this.heapDumper == null) {
            this.heapDumper = createHeapDumper();
        }
        File file = createTempFile(live);
        this.heapDumper.dumpHeap(file, live);
        return new TemporaryFileSystemResource(file);
    }

    private File createTempFile(boolean live) throws IOException {
        String date = new SimpleDateFormat("yyyy-MM-dd-HH-mm").format(new Date());
        File file = File.createTempFile("heapdump" + date + (live ? "-live" : ""),
                ".hprof");
        file.delete();
        return file;
    }

    /**
     * Factory method used to create the {@link HeapDumper}.
     * @return the heap dumper to use
     * @throws HeapDumperUnavailableException if the heap dumper cannot be created
     */
    protected HeapDumper createHeapDumper() throws HeapDumperUnavailableException {
        return new HotSpotDiagnosticMXBeanHeapDumper();
    }
}

这里调用的是dumpHeap方法,委托给heapDumper来执行

heapDumper

    /**
     * Factory method used to create the {@link HeapDumper}.
     * @return the heap dumper to use
     * @throws HeapDumperUnavailableException if the heap dumper cannot be created
     */
    protected HeapDumper createHeapDumper() throws HeapDumperUnavailableException {
        return new HotSpotDiagnosticMXBeanHeapDumper();
    }

    /**
     * Strategy interface used to dump the heap to a file.
     */
    @FunctionalInterface
    protected interface HeapDumper {

        /**
         * Dump the current heap to the specified file.
         * @param file the file to dump the heap to
         * @param live if only <em>live</em> objects (i.e. objects that are reachable from
         * others) should be dumped
         * @throws IOException on IO error
         * @throws InterruptedException on thread interruption
         */
        void dumpHeap(File file, boolean live) throws IOException, InterruptedException;

    }

    /**
     * {@link HeapDumper} that uses {@code com.sun.management.HotSpotDiagnosticMXBean}
     * available on Oracle and OpenJDK to dump the heap to a file.
     */
    protected static class HotSpotDiagnosticMXBeanHeapDumper implements HeapDumper {

        private Object diagnosticMXBean;

        private Method dumpHeapMethod;

        @SuppressWarnings("unchecked")
        protected HotSpotDiagnosticMXBeanHeapDumper() {
            try {
                Class<?> diagnosticMXBeanClass = ClassUtils.resolveClassName(
                        "com.sun.management.HotSpotDiagnosticMXBean", null);
                this.diagnosticMXBean = ManagementFactory.getPlatformMXBean(
                        (Class<PlatformManagedObject>) diagnosticMXBeanClass);
                this.dumpHeapMethod = ReflectionUtils.findMethod(diagnosticMXBeanClass,
                        "dumpHeap", String.class, Boolean.TYPE);
            }
            catch (Throwable ex) {
                throw new HeapDumperUnavailableException(
                        "Unable to locate HotSpotDiagnosticMXBean", ex);
            }
        }

        @Override
        public void dumpHeap(File file, boolean live) {
            ReflectionUtils.invokeMethod(this.dumpHeapMethod, this.diagnosticMXBean,
                    file.getAbsolutePath(), live);
        }

    }

这里创建的是HotSpotDiagnosticMXBeanHeapDumper,利用反射调用HotSpotDiagnosticMXBean的dumpHeap方法

TemporaryFileSystemResource

最后通过TemporaryFileSystemResource返回 ``` private static final class TemporaryFileSystemResource extends FileSystemResource {

    private final Log logger = LogFactory.getLog(getClass());

    private TemporaryFileSystemResource(File file) {
        super(file);
    }

    @Override
    public ReadableByteChannel readableChannel() throws IOException {
        ReadableByteChannel readableChannel = super.readableChannel();
        return new ReadableByteChannel() {

            @Override
            public boolean isOpen() {
                return readableChannel.isOpen();
            }

            @Override
            public void close() throws IOException {
                closeThenDeleteFile(readableChannel);
            }

            @Override
            public int read(ByteBuffer dst) throws IOException {
                return readableChannel.read(dst);
            }

        };
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new FilterInputStream(super.getInputStream()) {

            @Override
            public void close() throws IOException {
                closeThenDeleteFile(this.in);
            }

        };
    }

    private void closeThenDeleteFile(Closeable closeable) throws IOException {
        try {
            closeable.close();
        }
        finally {
            deleteFile();
        }
    }

    private void deleteFile() {
        try {
            Files.delete(getFile().toPath());
        }
        catch (IOException ex) {
            TemporaryFileSystemResource.this.logger.warn(
                    "Failed to delete temporary heap dump file '" + getFile() + "'",
                    ex);
        }
    }

    @Override
    public boolean isFile() {
        // Prevent zero-copy so we can delete the file on close
        return false;
    }

}

```

小结

heapDump的实现是依赖HotSpotDiagnosticMXBean来,如果不存在则报HeapDumperUnavailableException,然后状态码返回STATUS_SERVICE_UNAVAILABLE。如果存在则默认dump存活的对象。

doc

  • Spring Boot Reference Guide

本文分享自微信公众号 - 码匠的流水账(geek_luandun),作者:go4it

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-04-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 聊聊spring cloud的LoadBalancerAutoConfiguration

    本文主要研究一下spring cloud的LoadBalancerAutoConfiguration

    codecraft
  • 聊聊spring cloud gateway的GlobalFilter

    本文主要研究一下spring cloud gateway的GlobalFilter

    codecraft
  • 聊聊servicecomb-saga的alpha-server

    alpha-server是servicecomb-saga的分布式事务协调中心,采用spring boot开发,可以直接从jar包启动,需要依赖mysql或pg...

    codecraft
  • 细说new与malloc的10点区别

    Tencent JCoder
  • 【手把手教你全文检索】Lucene索引的【增、删、改、查】

    前言   搞检索的,应该多少都会了解Lucene一些,它开源而且简单上手,官方API足够编写些小DEMO。并且根据倒排索引,实现快速检索。本文就简单的实现增...

    用户1154259
  • 聊聊servicecomb-saga的alpha-server

    alpha-server是servicecomb-saga的分布式事务协调中心,采用spring boot开发,可以直接从jar包启动,需要依赖mysql或pg...

    codecraft
  • Flutter 学习记2 - 首个应用

    void main() 是入口方法,=> 用于单行方法,就是函数签名和函数体间的连接符号,感觉作用和 Kotlin 的单行函数体用 = 类似。既然这样,把代码修...

    七适散人
  • 聊聊spring cloud的DiscoveryClientRouteDefinitionLocator

    本文主要研究一下spring cloud的DiscoveryClient Route Definition Locator

    codecraft
  • Arrays.asList java.lang.UnsupportedOperationException 异常

    但是有一小点注意,不能对该方法返回的list进行增删操作,因为该方法返回的是Arrays的内部类 Arrays.asList源码:

    夏洛克的猫
  • 有趣的卷积神经网络

    最近一直在研究深度学习,联想起之前所学,感叹数学是一门朴素而神奇的科学。F=G*m1*m2/r²万有引力描述了宇宙星河运转的规律,E=mc²描述了恒星发...

    天涯泪小武

扫码关注云+社区

领取腾讯云代金券