英文原文链接,译文链接,原文作者:Abhishek Gupta ,译者:有孚
本文会介绍一些JVM内存结构的基本概念,然后很快会讲到持久代,来看下Java SE 8发布后它究竟到哪去了。
基础知识
JVM只不过是运行在你系统上的另一个进程而已,这一切的魔法始于一个java命令。正如任何一个操作系统进程那样,JVM也需要内存来完成它的运行时操作。记住——JVM本身是硬件的一层软件抽象,在这之上才能够运行Java程序,也才有了我们所吹嘘的平台独立性以及WORA(一次编写,处处运行)。
快速过一遍JVM的内存结构
正如虚拟机规范所说的那样,JVM中的内存分为5个虚拟的区域。
- 堆
- 方法区(非堆)
- JVM栈
- 本地栈
- PC寄存器
堆
- 你的Java程序中所分配的每一个对象都需要存储在内存里。堆是这些实例化的对象所存储的地方。是的——都怪new操作符,是它把你的Java堆都占满了的!
- 它由所有线程共享
- 当堆耗尽的时候,JVM会抛出java.lang.OutOfMemoryError 异常
- 堆的大小可以通过JVM选项-Xms和-Xmx来进行调整
堆被分为:
- Eden区 —— 新对象或者生命周期很短的对象会存储在这个区域中,这个区的大小可以通过-XX:NewSize和-XX:MaxNewSize参数来调整。新生代GC(垃圾回收器)会清理这一区域。
- Survivor区 —— 那些历经了Eden区的垃圾回收仍能存活下来的依旧存在引用的对象会待在这个区域。这个区的大小可以由JVM参数-XX:SurvivorRatio来进行调节。
- 老年代 —— 那些在历经了Eden区和Survivor区的多次GC后仍然存活下来的对象(当然了,是拜那些挥之不去的引用所赐)会存储在这个区里。这个区会由一个特殊的垃圾回收器来负责。年老代中的对象的回收是由老年代的GC(major GC)来进行的。
方法区
也被称为非堆区域(在HotSpot JVM的实现当中)
它被分为两个主要的子区域
- 持久代 —— 这个区域会存储包括类定义,结构,字段,方法(数据及代码)以及常量在内的类相关数据。它可以通过-XX:PermSize及-XX:MaxPermSize来进行调节。如果它的空间用完了,会导致java.lang.OutOfMemoryError: PermGen space的异常。
- 代码缓存——这个缓存区域是用来存储编译后的代码。编译后的代码就是本地代码(硬件相关的),它是由JIT(Just In Time)编译器生成的,这个编译器是Oracle HotSpot JVM所特有的。
JVM栈
- 和Java类中的方法密切相关
- 它会存储局部变量以及方法调用的中间结果及返回值
- Java中的每个线程都有自己专属的栈,这个栈是别的线程无法访问的。
- 可以通过JVM选项-Xss来进行调整
本地栈
- 用于本地方法(非Java代码)
- 按线程分配
PC寄存器
- 特定线程的程序计数器
- 包含JVM正在执行的指令的地址(如果是本地方法的话它的值则未定义)
好吧,这就是JVM内存分区的基础知识了。现在再说说持久代这个话题吧。
那么持久代上哪去了?
事实上,持久代在JDK8中已经被彻底删除了,取代它的是另一个内存区域也被称为元空间(MetaSpace)。
详见: http://ifeve.com/java-permgen-removed/
元空间 —— 快速入门
- 它是本地堆内存中的一部分
- 它可以通过-XX:MetaspaceSize和-XX:MaxMetaspaceSize来进行调整
- 当到达XX:MetaspaceSize所指定的阈值后会开始进行清理该区域
- 如果本地空间的内存用尽了会收到java.lang.OutOfMemoryError: Metadata space的错误信息。
- 和持久代相关的JVM参数-XX:PermSize及-XX:MaxPermSize将会被忽略掉。
当然了,这只是冰山一角。想要更深入地了解JVM,最好的资料莫过于它自己的虚拟机规范了!
相关推荐
堆内存用于存储类实例和数组,包括 молодой代(Young Generation)、老年代(Old Generation)和持久代(Permanent Generation)。非堆内存包括方法区(Method Area)和JVM为优化或内部处理所分配的内存。 ...
持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。 二、垃圾收集器选择 JVM提供了三种垃圾收集器:串行收集器、并行收集器、并发收集器。串行收集器只适用于小数据量的情况,因此这里的选择主要...
3. **持久代/元空间**:如果加载大量类导致`PermGen space`不足,可以增大`-XX:MaxPermSize`和`-XX:PermSize`,并保持两者相等以避免频繁扩展。 4. **栈深度**:若递归过深导致`StackOverflowError`,应检查代码...
JVM内存主要分为新生代、老年代和持久代,每个区域都有其特定的垃圾回收策略。 1. 引用计数法(Reference Counting):这是一种简单的垃圾回收算法,但无法处理循环引用,容易导致内存泄漏。 2. 标记-清除法(Mark...
堆内存是Java对象的主要存储区域,分为新生代(Young Generation)、老年代(Tenured Generation)和持久代(Permanent Generation或Metaspace)。新生代进一步划分为Eden区、Survivor区(S0和S1)。对象首先在Eden...
- **堆内存**:分为年轻代、老年代和持久代,理解每个区域的作用和GC策略对于优化内存使用至关重要。 - **垃圾回收(GC)**:监视GC活动,包括GC次数、耗时和内存分配情况,可以帮助识别可能的性能瓶颈。 - **...
- **Full GC**:年老代被写满、持久代被写满、显示调用`System.gc()`、上一次GC之后Heap的各域分配策略动态变化、RMI等的定时触发。 #### 五、JVM监控与故障处理工具 JVM提供了多种工具帮助开发者监控JVM的状态...
* -XX:MaxPermSize=n: 设置持久代大小 收集器设置: * -XX:+UseSerialGC: 设置串行收集器 * -XX:+UseParallelGC: 设置并行收集器 * -XX:+UseParalledlOldGC: 设置并行年老代收集器 * -XX:+UseConcMarkSweepGC: ...
-Xmn 设置年轻代的大小,整个 JVM 内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为 64m,所以增大年轻代后,将会减小年老代大小。Sun 官方推荐配置为整个堆的 3/8。 -Xss 设置每个线程的...
JVM内存分为新生代、老年代和持久代(在某些JVM实现中是元空间)。垃圾收集器通过不同的算法(如可达性分析、引用计数等)判断对象是否可回收,并进行垃圾清理。 ### 类加载机制 JVM遵循双亲委派模型加载类,从...
对象的生命周期与鱼的生长周期相比较,JVM利用不同的内存区域——年轻代、老年代和持久代,来适应不同生命周期的对象。年轻代主要用于存放新生的对象,它由Eden和两个Survivor区组成,新生对象首先在Eden区分配内存...
2. 分代内存模型:JVM将内存分为新生代、老年代和持久代,根据对象生命周期的不同,进行不同策略的垃圾收集,提高了内存利用率和程序性能。 三、类加载机制 1. 类加载器:Java 11中,JVM的类加载器系统确保了类的...
- **PermGen Space与Metaspace**:在早期版本的JVM中,持久代(PermGen Space)用于存放类的元数据等信息。从Java 8开始,PermGen Space被Metaspace取代,后者使用本机内存而不是堆内存。 ##### 3.4 方法区域...
堆内存分为新生代(Young Generation)、老年代(Tenured Generation)和持久代(Permanent Generation,Java 8后被元空间Metaspace替代)。 - **新生代**:主要存放新创建的对象,分为Eden区、From Survivor和To ...
除了年轻代和老年代,还有持久代(PermGen,Java 8之后被元空间Metaspace取代),它存放类和方法的元数据信息。 垃圾回收是JVM内存管理的关键部分,它涉及到垃圾回收器的选择和使用。不同的垃圾回收器适用于不同的...
- **堆内存**:JVM Monitor可以显示堆内存的使用情况,包括新生代、老年代和持久代的大小、利用率以及垃圾收集情况。通过监控这些指标,开发者可以识别是否存在内存泄漏或过度分配的问题。 - **非堆内存**:还包括...
- **持久代**(Permanent Generation):主要用于存放静态文件如Java类和方法等。对于使用大量动态类的应用程序,需要设置较大的持久代空间。 #### 二、垃圾回收器 JVM提供了多种类型的垃圾回收器,以适应不同应用...
在实际应用中,MAT不仅限于排查内存泄漏,还可以用于优化内存配置,例如调整堆大小、新生代和老年代的比例,以及了解应用对持久代、元空间等其他内存区域的影响。同时,MAT提供的插件和扩展功能也使得分析更加灵活和...
分代收集算法是根据对象的生命周期将其分为年青代、年老代和持久代(或称为永久代),并针对不同代的对象使用不同的垃圾回收策略。这种算法在现代的垃圾回收器中都有所应用。 按照系统线程分,垃圾回收算法分为串行...