首页 > 技术文章 > JVM 原理

huanghzm 2019-06-14 17:42 原文

引言

   JVM一直是java知识里面进阶阶段的重要部分,如果希望在java领域研究的更深入,则JVM则是如论如何也避开不了的话题,本系列试图通过简洁易读的方式,讲解JVM必要的知识点。

运行流程

  java代码通过编译之后生成字节码文件(class文件),通过:java HelloWorld执行,此时java根据系统版本找到jvm.cfg,再通过jvm.cfg文件找到对应的jvm.dll,jvm.dll则是java虚拟机的主要实现;初始化jvm,获取java本地接口,然后找到main方法,最后执行。详见下图

内存空间

  JVM内存空间包含:方法区、java堆、java栈、本地方法栈。

  方法区:是各个线程共享的区域,存放类信息、常量、静态变量。

  java堆:是线程共享的区域,我们的类的实例就放在这个区域,可以想象你的一个系统会产生很多实例,因此java堆的空间也是最大的。如果java堆空间不足了,程序会抛出OutOfMemoryError异常。内存溢出

  java栈:是每个线程私有的区域,它的生命周期与线程相同,一个线程对应一个java栈,每执行一个方法就会往栈中压入一个元素,这个元素叫“栈帧”,而栈帧中包括了方法中的局部变量、用于存放中间状态值的操作栈。

  本地方法栈:java栈类似,只不过它是用来表示执行本地方法的,本地方法栈存放的方法调用本地方法接口,最终调用本地方法库,实现与操作系统、硬件交互的目的。

  PC寄存器:程序执行的顺序,控制程序指令的执行顺序

  执行引擎:根据PC寄存器调配的指令顺序,依次执行程序指令。

内存溢出

  1. OutOfMemoryError:PermGen space(源程序中使用大量的jar或class)

    a、增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小;在catalina.sh 或catalina.bat文件中一系列环境变量名说明结束处(大约在70行左右) 增加一行: JAVA_OPTS=" -XX:PermSize=64M -XX:MaxPermSize=128m"

    b、清理应用程序中lib下的jar包

  2. OutOfMemoryError:Java heap space(java虚拟机创建的对象太多)

    a、检查程序是否有死循环或创建大量对象。

    b、增加Java虚拟机中Xms(初始堆大小)和Xmx(最大堆大小)参数的大小。如:set JAVA_OPTS= -Xms256m -Xmx1024m

  3. OutOfMemoryError:unable to create new native thread(JVM已经被系统分配了大量的内存,并且它至少要占用可用内存的一半)

    a、jvm参数中添加-Xss128k将线程栈内存大小设置为128k

JVM配置参数

  JVM配置的参数分为三种:跟踪参数、堆分配参数、栈分配参数

跟踪参数

  1、当发生GC(垃圾回收)时,打印GC简要信息

  使用-XX:+PrintGC或-verbose:gc参数

  2、打印GC的详细信息以及堆使用详细信息

  使用-XX:+PrintGCDetails参数

  3、使用外部文件记录GC的日志

  使用-Xloggc:log/gc.log

  4、监控类的加载

  使用-XX:+TraceClassLoading

堆配置参数

  指定最大堆,最小堆:Xmx、Xms

    -Xms等价于-XX:InitalHeapSize 表示堆内存初始大小

    -Xmx等价于-XX:MaxHeapSize 表示最大堆内存大小,可使用jinfo -flag MaxHeapSize 进程id查看

    -Xss等价于-XX:InitalStackSize 表示线程栈的初始大小,可以使用jinfo -flag ThreadStackSize 进程id查看,

  最大堆也就是Xmx参数指定的大小,表示java程序最大能使用多少内存大小,如果超过这个大小,那么java程序会报:out of memory(内存溢出)

  堆分配参数的总结

  永久区分配参数:-XX:PermSize -XX:MaxPermSize

  栈大小分配参数:栈大小参数为-Xss,通常只有几百k,决定了函数调用的深度,每个线程都有自己独立的栈空间。如果函数调用太深,超过了栈的大小,则会抛出java.lang.StackOverflowError,通常我们遇到这种错误,不是去调整-Xss参数,而是应该去调查函数调用太深的原理,是否使用递归,能不能保证递归出口等。

垃圾回收算法

  java语言与C语言最大的区别就是内存自动回收

  垃圾回收算法:1、引用计数法;2、标记清除

  垃圾回收器:

    1. 串行收集器:-XX:+UseSerialGC

    2. 并行回收器:

      a、ParNew回收器:-XX:+UseParNewGC

      b、Parallel回收器:-XX:+UseParallelGC

    3. CMS回收器:-XX:+UseConcMarkSweepGC

    4. G1回收器:-XX:+UseG1GC

 JDK与JRE的区别

  Java 运行时环境(JRE-Java Runtime Environment),它包括 Java 虚拟机、Java 核心类库和支持文件,但并不包含开发工具(JDK-Java Development Kit)——编译器、调试器和其他工具。

  Java 开发工具包(JDK)是完整的 Java 软件开发包,包含了 JRE,编译器和其他的工具(比如 JavaDoc, Java 调试器),可以让开发者开发、编译、执行 Java 应用程序。

推荐阅读