一、JVM内存结构图

JDK1.7以前

java 内存队列应用demo java内存结构图_Java

JVM内存结构主要有三大块:堆内存方法区

  • 堆内存是JVM中最大的一块,是线程共享的区域,由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下年轻代的这3种空间年轻代按照8:1:1的比例来分配
  • 方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆)
  • 栈又分为java虚拟机栈和本地方法栈主要用于方法的执行

JDK1.8以后

java 内存队列应用demo java内存结构图_方法区_02

以前的方法区(或永久代),用来存放class,Method等元数据信息,但在JDK1.8已经没有了,取而代之的是MetaSpace(元空间),元空间不在虚拟机里面,而是直接使用本地内存。

为什么要用元空间代替永久代?

  1. 类以及方法的信息比较难确定其大小,因此对于永久代的指定比较困难,太小容易导致永久代溢出,太大容易导致老年代溢出。
  2. 永久代会给GC带来不需要的复杂度,并且回收效率偏低。

二、JVM架构

java 内存队列应用demo java内存结构图_jvm_03

1.Class Loader类加载器

负责加载.class文件,至于class文件是否可以运行,则由Execution Engine决定。JVM01-类加载机制

2.Execution Engine 执行引擎

执行包在装载类的方法中的指令,也就是方法。

3.Runtime data area 运行数据区

      从整个计算机内存中开辟一块内存存储Jvm需要用到的对象,变量等,分为:方法区,堆,虚拟机栈,程序计数器,本地方法栈。

java 内存队列应用demo java内存结构图_Java_04

3.1 Java堆(Heap)

  • Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。
  • 此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
  • Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC堆”。
  • Java堆中还可以细分为:新生代和老年代;新生代又可以分为Eden空间、From Survivor空间、To Survivor空间。

堆是理解Java GC机制最重要的区域,没有之一

  结构:新生代(Eden区+2个Survivor区)  老年代 

  新生代:新创建的对象——>Eden区 

  GC之后,存活的对象由Eden区 Survivor区0进入Survivor区1   

  再次GC,存活的对象由Eden区 Survivor区1进入Survivor区0 

  老年代:对象如果在新生代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来,默认是15次),则会被复制到老年代

  如果新创建对象比较大(比如长字符串或大数组),新生代空间不足,则大对象会直接分配到老年代上(大对象可能触发提前GC,应少用,更应避免使用短命的大对象)

  老年代的空间一般比新生代大,能存放更多的对象,在老年代上发生的GC次数也比年轻代少

  • 通过-Xmx和-Xms可分配堆内存大小。
  • 如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

3.2  方法区(Method Area)

java 内存队列应用demo java内存结构图_java_05

  • 与Java堆一样,是各个线程共享的内存区域。用于存储虚拟机加载的:静态变量+常量+类信息+运行时常量池
  • 默认最小值为16MB,最大值为64MB,可以通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小
  • JDK1.6使用永久代实现方法区;JDK1.8使用元空间实现方法区

java 内存队列应用demo java内存结构图_java 内存队列应用demo_06

JDK1.8不再使用 JVM内存结构管理方法区的内存,而使用操作系统的本地内存(物理内存)

3.3  程序计数器(Program Counter Register)

java 内存队列应用demo java内存结构图_方法区_07

每个线程都有一个程序计算器,就是一个指针,指向方法区中的方法字节码(下一个将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。

3.4 JVM栈(JVM Stacks)

java 内存队列应用demo java内存结构图_java_08

  • Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。
  • 每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
  • 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。

3.5 本地方法栈(Native Method Stacks)

  • Native Method Stack中登记native方法,在Execution Engine执行时加载native libraies
  • 本地方法栈与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务

 

java 内存队列应用demo java内存结构图_Java_09

三、JVM 调参

jvm常用参数

含义

-XX:+PrintGC/-verbose:gc

打印GC的简要信息

-XX:+PrintGCDetails

打印GC的详细信息

-XX:+PrintGCDateStamps

打印GC发生的时间

-Xloggc:log/gc.log

指定GC的log位置,以文件输出

-XX:+PrintHeapAtGC

每一次GC后都打印堆信息

-XX:+HeapDumpOnOutOfMemoryError

当JVM发生OOM时,自动生成DUMP文件

-XX:HeapDumpPath=${目录}

生成的DUMP文件的存放位置

-Xms

初始堆大小,默认是物理内存的1/64

-Xmx

最大堆大小 默认是物理内存的1/4

-Xmn

年轻代的大小,默认整个堆的3/8

-Xss

设置每个线程的堆栈大小

-XX:MetaspaceSize

初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值

-XX:MaxMetaspaceSize

空间最大内存,默认是没有限制的

-XX:MaxDirectMemorySize

限制堆外内存的使用

-XX:+DisableExplicitGC

禁用 System.gc 显式FullGC

-XX:ReservedCodeCacheSize

调整JIT编译代码缓存

-XX:PretenureSizeThreshold

大于这个值的对象直接在老年代分配

-XX:+PrintGCApplicationConcurrentTime

打印每次垃圾回收前,程序未中断的执行时间

-XX:+PrintGCApplicationStoppedTime

打印垃圾回收期间程序暂停的时间