`

【深入Java编程】JVM源码分析之堆外内存完全解读

阅读更多
概述
广义的堆外内存
说到堆外内存,那大家肯定想到堆内内存,这也是我们大家接触最多的,我们在jvm参数里通常设置-Xmx来指定我们的堆的最大值,不过这还不是我们理解的Java堆,-Xmx的值是新生代和老生代的和的最大值,我们在jvm参数里通常还会加一个参数-XX:MaxPermSize来指定持久代的最大值,那么我们认识的Java堆的最大值其实是-Xmx和-XX:MaxPermSize的总和,在分代算法下,新生代,老生代和持久代是连续的虚拟地址,因为它们是一起分配的,那么剩下的都可以认为是堆外内存(广义的)了,这些包括了jvm本身在运行过程中分配的内存,codecache,jni里分配的内存,DirectByteBuffer分配的内存等等

狭义的堆外内存
而作为java开发者,我们常说的堆外内存溢出了,其实是狭义的堆外内存,这个主要是指java.nio.DirectByteBuffer在创建的时候分配内存,我们这篇文章里也主要是讲狭义的堆外内存,因为它和我们平时碰到的问题比较密切

JDK/JVM里DirectByteBuffer的实现
DirectByteBuffer通常用在通信过程中做缓冲池,在mina,netty等nio框架中屡见不鲜,先来看看JDK里的实现:

    DirectByteBuffer(int cap) {                   // package-private

        super(-1, 0, cap, cap);
        boolean pa = VM.isDirectMemoryPageAligned();
        int ps = Bits.pageSize();
        long size = Math.max(1L, (long)cap + (pa ? ps : 0));
        Bits.reserveMemory(size, cap);

        long base = 0;
        try {
            base = unsafe.allocateMemory(size);
        } catch (OutOfMemoryError x) {
            Bits.unreserveMemory(size, cap);
            throw x;
        }
        unsafe.setMemory(base, size, (byte) 0);
        if (pa && (base % ps != 0)) {
            // Round up to page boundary
            address = base + ps - (base & (ps - 1));
        } else {
            address = base;
        }
        cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
        att = null;



    }
通过上面的构造函数我们知道,真正的内存分配是使用的Bits.reserveMemory方法

    static void reserveMemory(long size, int cap) {
        synchronized (Bits.class) {
            if (!memoryLimitSet && VM.isBooted()) {
                maxMemory = VM.maxDirectMemory();
                memoryLimitSet = true;
            }
            // -XX:MaxDirectMemorySize limits the total capacity rather than the
            // actual memory usage, which will differ when buffers are page
            // aligned.
            if (cap <= maxMemory - totalCapacity) {
                reservedMemory += size;
                totalCapacity += cap;
                count++;
                return;
            }
        }

        System.gc();
        try {
            Thread.sleep(100);
        } catch (InterruptedException x) {
            // Restore interrupt status
            Thread.currentThread().interrupt();
        }
        synchronized (Bits.class) {
            if (totalCapacity + cap > maxMemory)
                throw new OutOfMemoryError("Direct buffer memory");
            reservedMemory += size;
            totalCapacity += cap;
            count++;
        }

    }
通过上面的代码我们知道可以通过-XX:MaxDirectMemorySize来指定最大的堆外内存,那么我们首先引入两个问题

堆外内存默认是多大
为什么要主动调用System.gc()
堆外内存默认是多大
如果我们没有通过-XX:MaxDirectMemorySize来指定最大的堆外内存,那么默认的最大堆外内存是多少呢,我们还是通过代码来分析

上面的代码里我们看到调用了sun.misc.VM.maxDirectMemory()
阅读全文直接点击:http://click.aliyun.com/m/9972/
分享到:
评论
1 楼 maobaolong 2017-10-17  
引用
真正的内存分配是使用的Bits.reserveMemory方法


真正的内存分配是这句吧,
base = unsafe.allocateMemory(size);

相关推荐

    jvm源码解读以及jvm调优,看的过程中会把c-c++文件也会放到里面进行解读-jvm-original.zip

    以上是对JVM源码解读和调优的全面解析,结合C/C++的视角,有助于开发者深入理解JVM的工作原理,提升Java应用程序的性能。在学习过程中,应结合具体项目实践,不断探索和优化,以达到最佳的运行效果。

    jvm调优.zip & hotspot源码解读

    在Java编程世界中,JVM(Java Virtual Machine)扮演着至关重要的角色。它负责运行Java应用程序,是Java“一次编写,到处运行”理念的核心。JVM调优是提升Java应用性能的关键步骤,而深入理解Hotspot源码则有助于...

    Java - JVM: 读书笔记 Chapter 05 The Java Virtual Machine ( Part I Basic )

    **源码和工具**:了解JVM的源码有助于开发者更深入地理解其工作原理,同时,工具如JVisualVM、JConsole和JProfiler等可以帮助开发者监控和分析JVM的运行状态,包括内存使用、线程状态、CPU负载等,以优化应用程序的...

    Java rt.jar 源码分析

    深入理解rt.jar的源码对于提升Java编程技能和优化性能至关重要。 首先,我们来看一下rt.jar中的主要组成部分。rt.jar包含了许多Java API的实现,这些API被组织在不同的包下,如`java.lang`、`java.util`、`java.io`...

    Java SE 源码 Java SE 源码

    源码分析可以了解注解的处理流程,以及如何自定义注解处理器。 通过深入学习这些源码,开发者可以提升对Java的理解,优化代码性能,甚至为Java社区贡献自己的改进。记住,源码是学习的最好教材,它揭示了软件设计的...

    jvm日志解读

    《JVM日志解读——揭示Java虚拟机的秘密》 在Java开发中,JVM(Java Virtual Machine)扮演着至关重要的角色。它负责运行我们的代码,管理内存,执行垃圾收集等。当程序出现异常或者性能问题时,JVM生成的日志文件...

    java源码解读-JavaSource:Java源码解读

    在Java编程语言的世界里,源码解读是提升技术深度、理解内部机制的关键步骤。"JavaSource:Java源码解读"项目旨在帮助开发者深入探索Java的内部工作原理,从而更好地运用和优化代码。在这个项目中,我们可以看到一...

    java源码解读-java-src:java源码解读

    Java源码解读是Java开发人员深入理解平台工作原理和编程模型的重要途径。在这个"java-src:java源码解读"项目中,我们可以探索Java的核心库,包括JVM(Java虚拟机)、集合框架、并发机制、I/O流、网络编程等多个关键...

    Java底层知识点、源码解读,技术栈相关原理知识点、工具解读最佳实践、功能点实战,问题排查,开发技巧等

    Java作为一门广泛使用的编程语言,其底层知识点和源码解读对于深入理解并优化代码性能至关重要。本主题将探讨以下几个方面: 1. **Java虚拟机(JVM)**: JVM是Java程序运行的基础,它负责字节码的解释执行,内存...

    Java 性能优化 一书源码

    《Java性能优化》一书深入探讨了如何通过各种技术提升Java应用程序的效率和响应速度。以下是一些基于书籍源码和相关文件名的关键知识点: 1. **命令行脚本**: 文件`javas.cmd`和`allcmd.cmd`可能是用于运行和测试...

    java源码解读-ITG-JavaBook01:Java面试高频源码解读

    深入理解JVM内存结构(堆、栈、方法区等)及垃圾回收机制(GC)对优化程序性能至关重要。通过分析对象创建、内存分配、垃圾回收等源码,可以深入理解JVM的工作原理。 五、反射与注解 Java反射API允许我们在运行时...

    深入剖析Tomcat+源码

    《深入剖析Tomcat》是一本专注于Java Web服务器Tomcat的深度解析资料,包含了对Tomcat源码的细致分析。此资料包提供了多个文件,包括"深入剖析Tomcat源码.rar","深入剖析tomcat.pdf",以及"apache-tomcat-7.0.32-...

    Java底层知识点、源码解读,技术栈相关原理知识点、工具解读最佳实践、功能点实战,问题排查,开发技巧等.zip

    了解JVM如何加载类、执行字节码、内存管理(包括堆、栈、方法区等)、垃圾收集(GC)策略以及性能优化等方面,对于提升程序效率和解决内存泄漏等问题至关重要。 其次,源码解读是提升技术水平的重要途径。Java标准...

    JVM崩溃

    标题中的“JVM崩溃”指的是Java虚拟机(Java Virtual Machine)在运行过程中遇到了无法处理的错误,导致程序异常终止的现象。这通常是由于内存溢出、类装载错误、线程死锁或其他严重问题引起的。理解JVM崩溃的原因和...

    JDK源码选读

    10. **JVM内存模型**:JDK源码也涉及JVM内存模型,如栈内存、堆内存、方法区等,有助于理解JVM的工作原理和性能调优。 通过《JDK源码选读》,开发者不仅能深化对Java语言的理解,还能学习到软件设计模式和最佳实践...

    系统解析JDK源码,领略大牛设计思想,JAVA进阶必备(2023新课,已完结)

    在Java编程领域,深入理解JDK源码是提升技能、进阶高级开发者的必经之路。"系统解析JDK源码,领略大牛设计思想,JAVA进阶必备"这一课程或资源包,旨在帮助开发者通过分析JDK源码,学习并掌握其中蕴含的设计模式和...

    tomcat源码分析

    【Tomcat源码分析】 Tomcat是一款开源的Java Servlet容器,是Apache软件基金会下的Jakarta项目的一部分。深入理解Tomcat的源码对于开发者来说是非常有价值的,因为它可以帮助我们更好地理解和优化Web应用程序的性能...

    Java-相关课程视频网盘地址.rar

    阿里面试总结 垂直打击之JVM剖析 大数据-大数据批处理之Hive详解 大数据-海量日志收集利器:Flume 分布式服务Dubbo的前世今生 高效程序员如何优雅落地...深入解读Tomcat8源码 深入浅出JVM 这辈子Tomcat源码是一定要看的

    java内存,性能分析工具Optimizeit Profiler介绍(类似MAT,JConsole等)

    Java内存管理和性能分析是开发高效率、高性能应用的关键环节。Optimizeit Profiler是一款强大的工具,专门用于Java应用程序的性能优化。它与MAT (Memory Analyzer Tool) 和JConsole等工具相似,提供了深入的内存和...

Global site tag (gtag.js) - Google Analytics