概述
广义的堆外内存
说到堆外内存,那大家肯定想到堆内内存,这也是我们大家接触最多的,我们在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/
分享到:
相关推荐
以上是对JVM源码解读和调优的全面解析,结合C/C++的视角,有助于开发者深入理解JVM的工作原理,提升Java应用程序的性能。在学习过程中,应结合具体项目实践,不断探索和优化,以达到最佳的运行效果。
在Java编程世界中,JVM(Java Virtual Machine)扮演着至关重要的角色。它负责运行Java应用程序,是Java“一次编写,到处运行”理念的核心。JVM调优是提升Java应用性能的关键步骤,而深入理解Hotspot源码则有助于...
**源码和工具**:了解JVM的源码有助于开发者更深入地理解其工作原理,同时,工具如JVisualVM、JConsole和JProfiler等可以帮助开发者监控和分析JVM的运行状态,包括内存使用、线程状态、CPU负载等,以优化应用程序的...
深入理解rt.jar的源码对于提升Java编程技能和优化性能至关重要。 首先,我们来看一下rt.jar中的主要组成部分。rt.jar包含了许多Java API的实现,这些API被组织在不同的包下,如`java.lang`、`java.util`、`java.io`...
源码分析可以了解注解的处理流程,以及如何自定义注解处理器。 通过深入学习这些源码,开发者可以提升对Java的理解,优化代码性能,甚至为Java社区贡献自己的改进。记住,源码是学习的最好教材,它揭示了软件设计的...
《JVM日志解读——揭示Java虚拟机的秘密》 在Java开发中,JVM(Java Virtual Machine)扮演着至关重要的角色。它负责运行我们的代码,管理内存,执行垃圾收集等。当程序出现异常或者性能问题时,JVM生成的日志文件...
在Java编程语言的世界里,源码解读是提升技术深度、理解内部机制的关键步骤。"JavaSource:Java源码解读"项目旨在帮助开发者深入探索Java的内部工作原理,从而更好地运用和优化代码。在这个项目中,我们可以看到一...
Java源码解读是Java开发人员深入理解平台工作原理和编程模型的重要途径。在这个"java-src:java源码解读"项目中,我们可以探索Java的核心库,包括JVM(Java虚拟机)、集合框架、并发机制、I/O流、网络编程等多个关键...
Java作为一门广泛使用的编程语言,其底层知识点和源码解读对于深入理解并优化代码性能至关重要。本主题将探讨以下几个方面: 1. **Java虚拟机(JVM)**: JVM是Java程序运行的基础,它负责字节码的解释执行,内存...
《Java性能优化》一书深入探讨了如何通过各种技术提升Java应用程序的效率和响应速度。以下是一些基于书籍源码和相关文件名的关键知识点: 1. **命令行脚本**: 文件`javas.cmd`和`allcmd.cmd`可能是用于运行和测试...
深入理解JVM内存结构(堆、栈、方法区等)及垃圾回收机制(GC)对优化程序性能至关重要。通过分析对象创建、内存分配、垃圾回收等源码,可以深入理解JVM的工作原理。 五、反射与注解 Java反射API允许我们在运行时...
《深入剖析Tomcat》是一本专注于Java Web服务器Tomcat的深度解析资料,包含了对Tomcat源码的细致分析。此资料包提供了多个文件,包括"深入剖析Tomcat源码.rar","深入剖析tomcat.pdf",以及"apache-tomcat-7.0.32-...
了解JVM如何加载类、执行字节码、内存管理(包括堆、栈、方法区等)、垃圾收集(GC)策略以及性能优化等方面,对于提升程序效率和解决内存泄漏等问题至关重要。 其次,源码解读是提升技术水平的重要途径。Java标准...
标题中的“JVM崩溃”指的是Java虚拟机(Java Virtual Machine)在运行过程中遇到了无法处理的错误,导致程序异常终止的现象。这通常是由于内存溢出、类装载错误、线程死锁或其他严重问题引起的。理解JVM崩溃的原因和...
10. **JVM内存模型**:JDK源码也涉及JVM内存模型,如栈内存、堆内存、方法区等,有助于理解JVM的工作原理和性能调优。 通过《JDK源码选读》,开发者不仅能深化对Java语言的理解,还能学习到软件设计模式和最佳实践...
在Java编程领域,深入理解JDK源码是提升技能、进阶高级开发者的必经之路。"系统解析JDK源码,领略大牛设计思想,JAVA进阶必备"这一课程或资源包,旨在帮助开发者通过分析JDK源码,学习并掌握其中蕴含的设计模式和...
【Tomcat源码分析】 Tomcat是一款开源的Java Servlet容器,是Apache软件基金会下的Jakarta项目的一部分。深入理解Tomcat的源码对于开发者来说是非常有价值的,因为它可以帮助我们更好地理解和优化Web应用程序的性能...
阿里面试总结 垂直打击之JVM剖析 大数据-大数据批处理之Hive详解 大数据-海量日志收集利器:Flume 分布式服务Dubbo的前世今生 高效程序员如何优雅落地...深入解读Tomcat8源码 深入浅出JVM 这辈子Tomcat源码是一定要看的
Java内存管理和性能分析是开发高效率、高性能应用的关键环节。Optimizeit Profiler是一款强大的工具,专门用于Java应用程序的性能优化。它与MAT (Memory Analyzer Tool) 和JConsole等工具相似,提供了深入的内存和...