JVM 原理
引言
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 应用程序。