Java虚拟机的内存结构
在程序运行时,JVM包含了两种运行时数据区,一种是与JVM同步存在的,在JVM启动时一直存在,直到JVM退出时才销毁,由所有的线程共享;另一种是与每个线程同步存在,线程退出则销毁。
运行时数据区包含如下几部分:
1, 程序计数器
每一个Java线程都有一个PC寄存器,用以记录在线程切换回来后恢复到正确的执行位置。
如该线程正在执行一个Java方法,则计数器记录的是正在执行的虚拟机字节码地址,如执行native方法,则计数器值为undefined。
因为只是记录线程执行时的返回地址,因此内存是足够使用的,该区域也是唯一一个在JVM中没有规定任何OutOfMemoryError情况的区域。
2,JVM栈
每个线程保持一个JVM私有栈,与线程一起创建,保存栈帧,栈帧用来存储局部变量,中间结果,以及方法返回值等。
该区域会抛出如下异常:
- If the computation in a thread requires a larger Java virtual machine stack than is permitted, the Java virtual machine throws a
StackOverflowError
. -
If Java virtual machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java virtual machine stack for a new thread, the Java virtual machine throws an
OutOfMemoryError
.
3,堆
堆空间是JVM中所有的线程共享的区域,在虚拟机启动时创建,堆空间不需要是连续的。用于存储所有的对象实例和数组。是垃圾收集管理的主要区域。
该区域会抛出如下异常:
The following exceptional condition is associated with the heap:
- If a computation requires more heap than can be made available by the automatic storage management system, the Java virtual machine throws an
OutOfMemoryError
.
4,方法区:
方法区是JVM中所有线程共享的区域,在虚拟机启动时创建,堆空间不需要是连续的。用于存储已加载的每个class的信息,比如运行时的常量池,字段和方法数据,方法的代码等。
方法区是堆的逻辑组成部分,但可以选择不对这个区域进行垃圾收集。方法区并不等同于永久代,但在虚拟机HotSpot实现时,方法区是在永久代中(JDK1.6及以下版本)。
该区域会抛出如下异常:
The following exceptional condition is associated with the method area:
- If memory in the method area cannot be made available to satisfy an allocation request, the Java virtual machine throws an
OutOfMemoryError.
5,运行时常量池:
运行时常量池是从方法区中分配出来的,在每一个类或者接口创建时,由JVM创建一个对应的常量池,用于存放各种常量数据,从编译时生成的各种字符数字到运行时需要用到的各种字段和方法引用。运行时常量池可以理解为是类或接口的常量池的运行时表现形式。
该区域会抛出如下异常:
The following exceptional condition is associated with the construction of the runtime constant pool for a class or interface:
- When creating a class or interface, if the construction of the runtime constant pool requires more memory than can be made available in the method area of the Java virtual machine, the Java virtual machine throws an
OutOfMemoryError
.
6,本地方法栈
Native Method Stacks 用来支持Native 方法,即不是使用Java语言写的方法。每个线程创建时,分配一个本地方法栈,
该区域会抛出如下异常:
The following exceptional conditions are associated with native method stacks:
- If the computation in a thread requires a larger native method stack than is permitted, the Java virtual machine throws a
StackOverflowError
. - If native method stacks can be dynamically expanded and native method stack expansion is attempted but insufficient memory can be made available, or if insufficient memory can be made available to create the initial native method stack for a new thread, the Java virtual machine throws an
OutOfMemoryError
.
JVM实现(HotSpot)的版本区别:
JDK1.7中,方法区已经转移到了堆中,运行时常量池也从堆空间中分配。
从JDK8开始,永久代(PermGen)的概念被废弃掉了,取而代之的是一个称为Metaspace的存储空间。Metaspace使用的是本地内存,而不是堆内存,也就是说在默认情况下Metaspace的大小只与本地内存大小有关。
JVM内存管理相关参数:
1,标准参数:功能和输出的参数都是很稳定的 在未来的JVM版本中不会改变 可以使用java -help检索出所有的标准参数。
2,X参数:非标准化参数 在未来的版本可能会改变 所有的参数都用-X开始 可以使用java -X检索 但是注意没有-Xcomp。
3,XX参数:非标准 很长一段时间不会列出来 用于JVM开发的debug和调优。
-XX:+<option> 启用option
-XX:-<option> 不启用option
-XX:<option>=<number> 设定option的值为数字类型,可跟单位,例如 32k, 1024m, 2g
-XX:<option>=<string> 设定option的值为字符串,例如-XX:HeapDumpPath=./dump.core
-Xms<size> 设置初始Java堆的大小。
-Xmx<size> 设置最大Java堆的大小。
-Xss<size> 设置Java线程堆栈大小。
-Xmn<size> 设置年轻代大小。
-XX:-DisableExplicitGC -XX:+DisableExplicitGC: 禁用显式垃圾收集, JVM任会在必要时执行垃圾收集。
-XX:+UseGCOverheadLimit 限制GC的运行时间,GC运行过长,则抛出OOM错误。
-XX:-UseParallelGC 新生代使用并行清除的垃圾收集器
-XX:-UseParallelOldGC 老年代和新生代都使用并行清除的垃圾收集器
-XX:-UseSerialGC 使用串行垃圾收集器
-XX:+UseG1GC 使用G1垃圾收集器
-XX: +UseConcMarkSweepGC 使用CMS垃圾收集器。
-XX:MaxGCPauseMillis=n 设置垃圾收集最大暂停时间
-XX:InitiatingHeapOccupancyPercent=n 设置触发垃圾收集的堆内存占用比,默认为45,如设置为0,则会一直不停的垃圾收集
-XX:NewRatio=n 老年代/新生代占用比值, 默认值为2,即新生代占用整个内存的1/3,老年代占用2/3.
-XX:NewSize=2m 新生代空间大小
-XX:SurvivorRatio=n Edon/Survivor 占用比值,默认值为8,新生代包含一个Edon区和2个Survivor区,默认值8,则代表一个Survivor区占用整个新生代的1/10
-XX:TargetSurvivorRatio=50 GC后,期望的Survivor区空间的占比
-XX:MaxTenuringThreshold=n 垃圾最大年龄,默认值为15
-XX:ParallelGCThreads=n 并行收集时的线程数,可配置为与处理器个数相同
-XX:ConcGCThreads=n 并行收集时的线程数,可配置为与处理器个数相同
-XX:G1ReservePercent=n 使用G1收集器时,设置保留堆的大小百分比,默认值为10
-XX:G1HeapRegionSize=n 设置Java堆被分割的区域大小,数值范围从1M到32M
-XX:LargePageSizeInBytes=4m 设置堆的内存页大小
-XX:MaxHeapFreeRatio=70 GC后,空余堆的大小占比值超过该比值,则缩小堆内存预估值。
-XX:MinHeapFreeRatio=40 GC后,空余堆的大小占比值小于该比值,则扩大堆内存预估值。
-XX:MaxNewSize=size 新生代占用的内存最大值
-XX:MaxPermSize=64m 永久代占用的内存最大值
-XX:HeapDumpPath=./java_pid<pid>.hprof 堆内存快照的存储路径
-XX:-HeapDumpOnOutOfMemoryError 当发生OOM错误时,输出一个堆内存快照文件
-XX:OnError="<cmd args>;<cmd args>" 当发生错误时,执行一个指令集,该指令集是与OS相关的,在Linux下是bash脚本,windows下是dos命令集。
-XX:OnOutOfMemoryError="<cmd args>; <cmd args>" 当发生OOM错误时,执行一个指令集,该指令集是与OS相关的,在Linux下是bash脚本,windows下是dos命令集。
-XX:-PrintGC 开启GC日志打印
-XX:-PrintGCDetails 打印GC时的详细信息
-XX:-PrintGCTimeStamps 打印GC操作时的时间戳
-XX:-PrintTenuringDistribution 打印对象的存活周期信息
-XX:+UseCompressedOops 在64位的机器上,压缩使用32位的类指针,以节约内存空间,适用于Java堆的大小不到32G时。
-XX:InitialTenuringThreshold=7 设置初始对象在新生代中最大存活次数
-XX:MaxTenuringThreshold=n 设置对象在新生代中最大存活次数
-XX:NumberOfGClogFiles=1 设置切分GC日志文件的数量,值>=1, 命名格式 filename.1, filename.2..... filename.n-1.
-XX:GCLogFileSize=8K 设置切分GC日志的大小,值>=8k.
内存的设置该怎么设置呢?设置成多大比较合适,既不浪费内存,又不影响性能呢?
依据的原则是根据Java Performance里面的推荐公式来进行设置。
具体来讲:
Java整个堆大小设置,Xmx 和 Xms设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍
永久代 PermSize和MaxPermSize设置为老年代存活对象的1.2-1.5倍。
年轻代Xmn的设置为老年代存活对象的1-1.5倍。
老年代的内存大小设置为老年代存活对象的2-3倍。
Sun官方建议年轻代的大小为整个堆的3/8左右
堆大小=年轻代大小+年老代大小, 即xmx=xmn+老年代大小 。 Permsize不影响堆大小。
如何确认老年代存活对象大小?
JVM参数中添加GC日志,GC日志中会记录每次FullGC之后各代的内存大小,观察老年代GC之后的空间大小。可观察一段时间内(比如2天)的FullGC之后的内存情况,根据多次的FullGC之后的老年代的空间大小数据来预估FullGC之后老年代的存活对象大小(可根据多次FullGC之后的内存大小取平均值)
参考资料:
https://docs.oracle.com/javase/specs/jvms/se6/html/VMSpecTOC.doc.html
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
相关推荐
java虚拟机的内存结构,关于内存的相关介绍等,想要了解更多JVM的
1、Java虚拟机内存结构模型 Java虚拟机内存结构分:JVM堆、方法区、虚拟机栈、本地方法栈、程序计数器。 JVM堆:所有线程共享的运行时内存区域,是GC回收的主场所,Java堆保存Java的实例对象,从内存回收对象的存活...
Java 虚拟机的内存结构包括方法区(method area)和堆(heap)。方法区保存了从类文件中解析出来的信息。堆保存了程序执行时创建的对象。每一个线程都有自己的 PC 寄存器(程序计数器)和 Java 堆栈(Java stack)。...
总结来说,基于Java虚拟机内存模型的性能调优涉及到多个层面,包括理解内存结构、垃圾回收机制、内存分配策略、调优工具的使用以及JVM参数的设置。通过深入理解和实践这些知识,开发者能够有效地优化Java应用程序,...
Java虚拟机(JVM)是一种能够运行Java字节码的虚拟机。它不仅可以运行Java语言编写的程序,还能够运行任何编译后符合JVM规范的其他语言的字节码。JVM由三个主要子系统构成:类加载子系统、运行时数据区、执行引擎。...
Java虚拟机的结构包括内存区域、执行引擎、类加载器系统等组件。内存区域主要分为堆、栈、方法区、本地方法栈和程序计数器等部分,每个都有特定的用途,例如,堆存储对象实例,栈处理方法调用,方法区存储类信息。...
第二章:java虚拟结构(运行时区域内存:寄存器,java虚拟机栈,java堆,方法去,运行时常量池,本地方法栈); 第三章:为java虚拟机编译; 第四章:Class文件格式; 第五章:加载、链接与初始化
JVM规范定义了JVM的内存结构,包括类加载器、执行引擎、运行时数据区域等。规范确保不同厂商的JVM实现可以兼容同一Java程序。 ##### 2.2 Sun/Oracle JVM Sun/Oracle是JVM的主要开发者之一,其JVM实现以性能优异著称...
Java虚拟机还负责垃圾回收(Garbage Collection),即自动管理内存,释放不再使用的对象占用的内存,减轻程序员的负担。垃圾回收机制是Java语言与生俱来的特性之一,与C/C++等语言相比,Java的内存管理更简单、更...
Java虚拟机的内部结构包括类装载器、运行时数据区、执行引擎、本地方法接口和本地库。其中,类装载器负责加载类文件,运行时数据区存储线程的工作数据,执行引擎解析并执行字节码,本地方法接口允许JVM调用非Java...
Java虚拟机(JVM,Java Virtual Machine)是Java平台的核心组成部分,它负责执行Java程序,为Java代码提供了跨平台的运行环境。Java虚拟机的概念始于Sun Microsystems,现在由Oracle公司继续发展和维护。JVM的设计...
Java虚拟机(JVM)内存结构是理解Java应用程序性能和内存管理的关键。本文将详细介绍JVM内存的不同组件,包括它们的功能和重要性。 首先,Java虚拟机规范中的内存管理主要涉及Runtime Data Area,这是一个用于存储...
根据提供的文件内容,以下是关于JAVA虚拟机(JVM)内存使用优化的知识点: 1. JVM内存优化的重要性:在运行Java应用程序时,尤其是涉及到大量数据查询和高并发操作的场合,系统可能由于内存溢出而不稳定。JVM内存...
这份文档不仅对Java虚拟机的基本原理进行了详尽的描述,还定义了Java虚拟机的运行时环境、内存布局、类文件结构等关键要素。这对于理解Java程序是如何被执行的非常重要。 #### 版本信息 该文档的原文版本发布于...
MiniJavaVM—个Java虚拟机的设计和实现 在本篇文章中,我们将详细介绍 MiniJavaVM 的设计和实现,包括其总体架构、功能、运行环境和开发工具,以及具体的实现步骤。 第一章绪论 Java 虚拟机(Java Virtual ...
Java虚拟机(JVM)是Java程序运行的核心,它的内存结构是理解Java性能优化和内存管理的关键。在Java虚拟机中,内存分为多个区域,主要包括以下几个部分: 1. **原始类型**:Java语言中,原始类型包括数值类型(如...
Java虚拟机的内存区域分为几个部分,其中包括线程私有的区域(程序计数器、Java虚拟机栈、本地方法栈)和线程共享的区域(Java堆、方法区、运行时常量池)。对象的访问是通过句柄或直接指针的方式来进行的。 在了解...
Java虚拟机的体系结构主要包括以下几个部分: 1. **类加载子系统**(Class Loader Subsystem):负责将Java类加载到内存中,并对它们进行验证、解析和初始化。每个Java应用程序都有一个类加载器子系统,该子系统...
3. **内存管理**:JVM内存结构包括堆、栈、方法区等,书中会讲解如何模拟这些区域,以及如何处理对象分配、垃圾回收等问题。 4. **执行引擎**:解释执行器或即时编译器(JIT)是JVM执行字节码的关键。书中会介绍...
《深入Java虚拟机》通常包含了JVM的详细剖析,涵盖了诸如类加载机制、字节码执行、内存管理、垃圾收集、性能优化等多个关键领域。书中可能详细解释了JVM如何将字节码转换为机器码,以及如何进行动态编译以提升运行...