一、java的内存模型
在谈java内存模型的时候我们先了解一下java程序的执行流程是是什么样的。首先我们编写的java源程序(*.java)文件,由java编译器(Java Compiler)编译成字节码文件(.class),然后由java虚拟机的类加载器加载各个类的字节码文件,加载完毕后交给jvm的执行引擎执行。
在整个程序执行过程中JVM会用一块空间来存储执行过程中需要用到的数据和相关信息,这块空间一般被称为运行时数据区(Runtime Data Area),也就是我们常说的JVM内存。因此我们常说的对JVM内存管理就是针对这一块空间进行管理(空间的分配和回收)。
二、运行时数据区(Runtime Data Area)
堆内存(Heap):保存所有引用数据类型的真实信息。
栈内存(Stack):基本类型、运算、指向堆内存的指针等。
方法区(Method Area): 所有定义的方法信息都保存在方法区中,共享区。
程序计数器(Program Counter Register):是一个很小的内存空间,小到可以忽略不计。
对引用数据类型访问有两种形式:1.通过句柄访问(C++)2.直接通过指针访问(Java)
三、JVM的型号
世界上有三种java虚拟机:
SUN公司最早改良的HotSpot;
BEA公司的JRockit;
IBM的JVM's;
JDK的几种模式:
所谓的混合模式指的是适合编译和执行 mixed modle
使用纯解释模式interpreted mode Java -Xint-version
使用纯编译模式启动compiled mode Java -Xcomp-version
-server:服务器模式,占用内存大,默认启动模式。
-client:本地单机运行程序模式,启动的速度快。
四、GC垃圾回收
java堆内存划分(1.8以前)
1.8以后
JVM将堆内存分为三块区域:
年轻代:新对象和没达到一定年龄的对象都在年轻代。
老年代:被长时间使用的对象,内存空间要比年轻代要大。
元空间:(1.8以后)像一些方法中的操作临时对象等,直接使用物理内存。
------ (1.8以前)最初永久代是需要将JVM堆内存里面进行划分。
对于整个的GC流程里面,那么最需要处理的就是年轻代和老年代的内存清理进行操作,
而元空间(永久代)都不在GC的范围内。
GC流程:
所有的数据都会保存在JVM的堆内存中,我们在实际开发过程中会持续产生对象。
一、 当现在有一个新的对象产生,那么对象一定需要内存空间,于是现在就需要为该对象进行内存空间的申请。
二、 首先会判断伊甸园区是否有内存空间,如果此时内存空间充足则将对象保存在伊甸园区。
三、 但是如果此时伊甸园内存空间不足,那么会自动执行一个MinorGC,将伊甸园区的无用内存空间进行清理,清理之后会继续判断伊甸园区的内存空间是否充足,如果充足则将新的对象进行内存分配。
四、 如果执行了MinorGc之后伊甸园区空间依然不足,那么这个时候会进行存活区的判断,如果存活区有剩余空间,则会将伊甸园区的部分活跃对象保存到存活区,
那么随后会继续判断伊甸园区内存空间是否充足,如果空间充足则进行新对象进行内存分配。
五、 如果此时存活区也已没有内存空间了,则将继续判断老年区,如果此时老年区空间充足,则将存活区的活跃对象保存到老年代,而后存活区会出现空余空间,而后伊甸园区将活跃对象保存在存活区之中,而在伊甸园区会为新对象进行内存分配。
六、 如果这个时候老年代也满了,那么这个时候会产生MajorGC(FullGC)进行老年代的内存清理。
七、 如果老年代执行FullGC后依然无法进行进行新对象的创建。则抛出OOM异常,
OutOfMemary内存溢出。
堆内存参数调整:(调优关键)
可变伸缩区:可变范围之内扩大内存空间,当一段时间后发现内存不那么紧张的时候,再将可变伸缩内存进行释放。
堆内存空间调整参数:
-Xmx 最大内存 占物理内存的1/4
-Xms 初始化内存 初始化内存占物理内存的1/64
-XX:+PrintGCDetails 打印GC的详细信息
可视化工具:jdk的bin的jvisualvm.exe
命令查看 jmap(jmap -heap PID) windows下查看进程id:taskList