欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java虚拟机内存结构 博客分类: java JavaJVM虚拟机内存结构运行时数据区

程序员文章站 2024-03-06 17:30:56
...

Java虚拟机的内存结构

 

      在程序运行时,JVM包含了两种运行时数据区,一种是与JVM同步存在的,在JVM启动时一直存在,直到JVM退出时才销毁,由所有的线程共享;另一种是与每个线程同步存在,线程退出则销毁。


Java虚拟机内存结构
            
    
    博客分类: java JavaJVM虚拟机内存结构运行时数据区

 

运行时数据区包含如下几部分:

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 *Error.
  • 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 *Error
  • 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虚拟机内存结构
            
    
    博客分类: java JavaJVM虚拟机内存结构运行时数据区

 

具体来讲:

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虚拟机内存结构
            
    
    博客分类: java JavaJVM虚拟机内存结构运行时数据区
  • 大小: 40 KB
  • Java虚拟机内存结构
            
    
    博客分类: java JavaJVM虚拟机内存结构运行时数据区
  • 大小: 22.8 KB