一、JVM介绍
jvm是java virtual machine 的简称,它是java虚构出来的计算机,有自己的指令集,寄存器和堆栈内存。它屏蔽了java应用程序与具体的操作平台相关的信息,java程序只需生成jvm的目标代码既字节码,jvm通过对字节码的解释最终转化为具体平台的指令,实现了java的跨平台。
二、内存简介
jvm结构可以看成是堆内存和非堆内存组成,堆是运行时内存对象的实例化,数组内存的分配都是由此内存划分。堆内存之外的称为非堆内存。堆内存是java代码可及的内存,而非堆内存是jvm留给自己使用的,例如内部优化所需的内存,类的信息,final常量,类的构造方法。(下第四部分有对此节的详细介绍)
三、垃圾回收(GC)
GC是jvm的垃圾回收,当实例化一个java对象的时候jvm为此对象分配一块内存,当此对象不再被使用时,由jvm自动回收此内存块。不用人为的释放内存,降低了内存溢出的风险。
GC算法通常有两种,一是引用计数,当对象创建、引用时该对象的计数增加,引用超出作用域或者对象为空的时候,此计数减少。当计数为0的时候此对象可以回收。二是对象引用遍历,也称向图法。就是从根开始沿着整个对象图遍历,标记可到达的对象。再通过扫描整个堆栈处理不可到达的对象。
这两种算法对应了多种实现机制
1,标记-清除
2,标记-压缩
这两种机制是对不可到达的对象进行清理、压缩处理。
3,复制机制
这种机制将堆栈分为两个区域,称为半空间。每次使用一半的空间,生成的新对象在一个空间GC时将可到达的对象复制到另一个空间,从而实现堆栈的压缩。
4,增量机制
这种机制是将内存分为多个区域,每次从一个区域进行垃圾回收。
5,分代机制
这个一个比较常用的机制,这种收集机制是将堆栈分为两个或多个区域。用于存放不同寿命的对象,根据对象的使用频率分配不同寿命的区域。
以上机制称为串行GC,GC的时候会造成程序的暂停,jvm还有基于多线程的GC,称为并行GC和并发GC,他们的扫描复制都是在多线程的基础上进行的不会造成程序的暂停,适用于多cpu和对暂停时间要求较短的应用程序。是server级默认的GC机制。
四、关于out of memory
这里有必要再重新详细的说一下jvm的结构。jvm分为堆内存和非堆内存,对内存分为新生代区、旧生代区,非堆内存称为永久区。新生代区又分为Eden和survivior区,survivor区分为FromSpace和toSpace
jvm在GC的时候对不同的区域进行了区别对待,对新生代区会进行频繁的GC,使用的是coyping机制,对旧生代区采用的是标记机制。
所有新创建的对象存在于Eden区,当Eden的内存不足时,将依旧存活的对象拷贝到survivor区中的FromSpace,ToSpace中的一个区。如果这个区也是不足的那么将此区域的存活的对象拷贝到另一个区,然后清除此区。就是说FromSpace和ToSpace总有一个是空的。对新生代的GC叫作minor GC,通常对象活不过这次GC
当一个Survivor的区满的时候,会将此区域中经过一定次数GC依旧活着的对象放到旧生代区,如果旧生代区满了的话就会发生FULL GC,Full GC相当耗资源,Full GC的时候应用程序会暂停。
永久区内存装载的类的信息,常量池,如果常量池无限大,或者要装载大量的class或者动态生成类。这个区域占有内存也会增大。也会发生FULL GC。
不论堆内存还是非堆内存内存虽然GC能释放一些内存空间,但是内存不足的情况还是会发生,
堆内存空间不足会出现 java.lang.OutOfMemoryError: heap space
非堆内存不足会出现 java.lang.OutOfMemoryError: PermGen space
堆内存大小设置参数 -Xms512m -Xmx512m
非堆内存大小设置参数 -XX:PermSize=256m -XX:MaxPermSize=256m
Xms指堆内存的初始值(默认物理内存的1/64),Xmx是指堆内存最大值(默认物理内存的1/4)。当堆内存的剩余空间不足40%的时候堆内存大小扩大到最大值Mmx,当剩余空间大于70%的时候堆内存减小为初始值。堆内存大小的变化也是消耗资源消耗性能的动作,将这两个参数设为一样可以避免堆内存变化带来的性能消耗(非堆内存同理)。