JVM
接上一篇博客,这里面我们来讨论一下java虚拟机,也就是jvm,在这里面我们主要关注其垃圾回收机制。
java的核心组成部分有class和执行引擎两部分组成,当执行引擎执行代码的时候,会从内存里面开辟出一段空间,这段内存区,大体由以下几个部分组成,如下图,这几部分有的是线程之间共享的,有的是独占的。
下面这图是jvm的核心组成部分,在关其中的介绍我在上一篇博客已经说过了,链接在此:
下文主要是来介绍一个jvm当中的堆,堆是java预留的一段空间,用来存放类执行之后生成的对象,我们知道JAVA不同于C,C需要程序员自己计算内存空间,而JAVA是“垃圾回收器”统一回收,回收的主要内容其实就是堆占用的空间,因为堆空间里面的对象可能调用一次就以后再也不用了,堆空间是最占内存的,而且堆是共享的,回收的时候是分代回收,有“年青代”,有“老年代”。
堆
堆结构
堆的结构如下所示:
堆内置的内存区域分为:
-
新生代(有垃圾回收机制)
-
老年代、有垃圾回收机制)
-
持久代、(没有垃圾回收机制)
新生代区域又分为:
-
eden(取自伊旬园,初始之意,执行对象的初始地,相当于新手村)
-
from(过了新手村之后,就会到达from区域,相当于第一阶段,又称ss1,可类比为少年时期)
-
to (过了第二阶段之后,会到达第三阶段,相当于第二阶段,又称ss2,可类比为中年时间)
NOTE:我们注意到在新生代当中还有reserved区域,这个区域是预留的区域,至于它的作用,我们后面会介绍的。
老年代区域又分为(老年代比较简单,敖过了中年时期才会到达老年代):
- 老年代空间
- 预留区域
持久代区域又分为(注意,持久代当中没有垃圾回收机制,熬过了老年代才会到达持久代):
- 持久代空间
- 预留区域
垃圾回收
对象移动过程:
- 对象刚出生的时候在新生代的eden区域,有的对象用完就不再用了,那么这个对象就在当前空间原地等待垃圾回收 。
- 如果这个对象在后面还会用一阵子,这个对象就会移动到from区域
- 如果这个对象在后面还会再用一阵子,这个对象就会由from移动到to区域
- 然后下次移动到老年代,最后移动到持久代
垃圾回收频率和算法:
无论是新生代还是老年代,都会有垃圾回收机制,只是回收的频率不一样,old次数更少,而且算法也不一样。
无论做什么事情,在初始阶段放弃的人总是非常多,能熬过入门阶段就很少有人放弃了。
新生代的垃圾回收算法是minor GC,也被称之为小GC。
老年代的垃圾回收算法是major GC,也被称之为full GC或大GC。
垃圾回收的注意点:
- 垃圾回收不是实时进行的,而是的攒一会再进行的。
- 垃圾回收的时候非常消耗cpu和内存,会把jvm内部给锁死,在当时的一瞬间会卡死,这也是安卓比苹果卡的原因,苹果的底层是实时回收的。
新生代垃圾回收过程(小GC算法):
老年代垃圾回收:
老年人垃圾回收比新生代要简单许多,大体可分为两个过程:
-
老年代在回收时首先要遍历老年代区域所有的对象,然后标记不再使用的对象。
-
清理不再使用的的对象。
老年代区域的垃圾回收频率比新生代要少,但是老年代在垃圾回收时是最卡的时候,因为要遍历整个老年代区域。
堆空间
新生代、老年代、持久代当中的空间大小是由我们进行指定的,但是并不能胡乱指定,要根据自己当前的业务进行指定。
我们可以在tomcat的配置文件里面指定,向jvm传递参数,也可以在命令行的当中用环境变量指定。
- -Xmx=新生代总空间+老年代总空间
- -XX:MaxNewSize新生代总空间
- -XX:NewSize新生代初始空间,不算预留空间,所谓的初始空间就是一开始的时候是多大
- -xms是新生代的初始空间和老年代的初始空间
- 老年代空间无法指定,用总空间减去新生代空间即为老年代空间,也就是说老年代空间是计算出来的。
- -XX:MaxPermSize持久代的总空间大小
- -XX:PermSize持久代的初始空间大小
tomcat而言
catalina.sh当中有两个环境变量
-
CATALINA_OPTS:仅对启动运行tomcat实例的java虚拟机有效。
-
JAVA_OPTS:对本机上的所有java虚拟机有效。
通过命令行的环境变量也可以向jvm传递参数,比如:
exports CATALINA_OPTS="-Xmx256m"