持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
JVM
JVM内存模型
- 1.内存结构图
- 2.内存模型
- 方法区/元空间:线程共享,存放已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
- 堆(heap):线程共享,JVM管理的内存中最大的一块,在虚拟机启动时创建,用于java类对象和数组对象分配内存的区域。是JVM垃圾回收的主要区域。
- 虚拟机栈(stack):属于线程私有,生命周期与线程相同,java方法执行时都会创建一个栈帧,用于存储局部变量、操作数栈、动态链接、方法出口等信息。每个方法被调用到执行结束就对应着一个栈帧从入栈到出栈的过程。
- 程序计数器:占用内存空间小,记录程序运行时的字节码行号,是JVM中唯一一块不会出现OOM的区域。
- 本地方法栈:与虚拟机栈相似,只不过虚拟机栈是为虚拟机执行java方法服务,而本地方法栈是为使用到native的方法服务。
2.如何确定一个对象为垃圾
- GC回收之前为了区分对象是否存活,要进行垃圾标记,主要采用以下两种方式确定为可回收垃圾对象。
- 引用计数法:如果一个变量引用对象A,A的引用计数就会+1,当引用失效时,引用计数就会-1,如果计数为0就可对其进行回收,但是这种方式可能产生两个对象相互循环引用,导致对象无法被回收。
- 根搜索算法:根搜索算法是以根为起点,按照从上到下的方式搜索被根对象集合所连接的目标对象是否可达,如果不可达就说明对象已死亡可回收。
3.常见垃圾回收算法
- 标记-清除算法:标记需要回收的对象,标记完成后统一回收所有被标记的对象。会产生大量的内存空间碎片,导致内存空间不连续,如果有大对象就不得不提前触发另一次垃圾回收。
- 复制算法:将可用内存按等容量划分为两块,每次只使用一块,就将原来存活的对象复制到另一块,然后把使用过的那块清理掉。解决了内存空间碎片的问题,但是将原来的内存缩小到了一半。
- 标记-整理算法:先标记出存活的对象,然后把所有存活的对象移动到一端,再直接把边界外的内存清理掉。解决了标记清除算法和复制算法遗留的问题。
- 分代收集算法:将对象存活周期的不同划分为几块, 通常都是分为新生代与老年代,再根据各年代采用合适的收集算法。
4.垃圾收集器
进行垃圾收集的时候,必须停止其他所有工作线程,简称STW(Stop The World)。
- Serial收集器:单线程收集器,在进行垃圾回收时需要STW,直到垃圾收集结束。所以该垃圾收集器体验比较差。
- PartNew收集器:Serial的多线程版本,除了采用多线程并行外,其他与Serial没区别。可通过-XX:+UseParNewGC手动指定使用PartNew收集器执行垃圾回收任务。
- Parrallel Scavenge:新生代收集器,也是采用复制算法的收集器,使用多线程并发收集,与PartNew不同的是它重点关注一个程序达到一个可控的吞吐量(吞吐量=工作线程运行时间/(工作线程运行时间+垃圾收集时间)),高吞吐量可以最高效利用CPU时间尽快的完成程序的运算任务,适用于不需要交互太多的任务。可通过以下两个参数精确控制吞吐量:
- -XX:MaxGCPauseMillis:设置最大GC停顿时间(GC pause time)指标(target). 这是一个软性指标(soft goal), JVM 会尽量去达成这个目标。
- -XX:GCTimeRatio:吞吐量收集器的目标是垃圾收集花费的时间与垃圾收集之外花费的时间(即应用程序时间)来衡量的。
- Parallel Old:老年代收集器,使用多线程标记整理算法。JDK1.6开始提供。
- CMS收集器:以最短停顿时间回收为目标的收集器,重视服务器相应速度,采用标记清除的算法进行垃圾回收。主要执行流程如下:
- 初始标记:整个STW的过程,标记GCRoots直接可达的对象。
- 并发标记:与应用线程并发执行,依据初始标记出来的对象递归标记可达对象。
- 并发重新标记:并发标记时应用线程也在运行,有可能在这个过程中又产生了垃圾对象,需要对其进行重复标记。
- 并发清除:与应用程序一直执行,并发清除垃圾对象。
5.JVM常用的启动参数
-
设置堆内存:-Xmx4g -Xms4g
-
指定GC算法:-XX:UseG1GC(使用G1收集器)
-
设置GC最大停顿时间:-XX:MaxGCPauseMillis=50(毫秒)
-
指定GC并发线程数:-XX:ParallelGCThreads=4
-
打印GC日志:-XX:PrintGCDetails -XX:PrintGCDateStamps
-
指定GC日志文件:-Xloggc:gc.log
-
指定Meta区的最大值:-XX:MaxMetaspaceSize=2g
-
设置单个线程栈的大小:-Xss1m
-
指定堆内存溢出时自动dump:-XX:HeapDumpOnOutOfMemoryError、-XX:HeapDumpPath:/usr/local