jvm优化总结 -- 理论
JVM内存组成部分:
- 线程共享的: 方法区+堆
- 线程独享: PC寄存器+栈+本地方法栈
具体:
- 栈:基本数据类型数据
- 堆:存储对象或者数组;
- 方法区:(记忆:类型信息+类变量+方法信息+常量池)
1、类型信息,例如类的全限定名、类型的修饰符
2、常量池: 字面量(类名,成员变量名等等))、符号引用(?)
3、方法信息,例如方法名、方法的返回类型、方法参数的类型,方法的修饰符
4、类变量
java编辑器:
Java程序从源文件创建到程序运行要经过两大步骤:
- 源文件由编译器编译成字节码(ByteCode)
- 字节码由java虚拟机解释运行。
因为java程序既要编译同时也要经过JVM的解释运行,所以说Java被称为半解释语言
编译后的字节码文件格式主要分为两部分:常量池和方法字节码。
堆内存:
共享内存:堆 + 方法区
堆:新生代 + 老年代
新生代: 伊甸园区 + 幸存区S0 + 幸存区S1
新生代:
- S0和S1空间相同 ;
- 相关算法:coping算法来分配内存和垃圾回收 youngGC 或 minorGC
- Eden区的对象量达到阈值后,发生一次新生代GC
- 通过-Xmn设置新生代的大小,通过-XX:SurvivorRatio 设置Eden区和Survivor区的比值,有些垃圾回收器会对S0或者S1进行动态的调整。
老年代:
- 在新生代中经过多次垃圾回收后仍然存活的对象,会存放在老生代 ;
- 老生代通过 mark算法 来清理无用内存 ; fullGC 或 majorGC
- 当年老代满时会引发Full GC,Full GC将会同时回收年轻代、年老代
- 当永久代满时也会引发Full GC,会导致Class、Method元信息的卸载
永久代:
- GC不会再主程序运行期间对 永久代进行清理,如果你的程序加载了很多class的话,请就能出现PermGen space错误
新生代的coping算法:
使用3个分区进行处理,默认比例是:Eden/S0/S1 为 8:1:1,可分配新生对象的内存是总内存的90%+
算法过程:
1. Eden+S0可分配新生对象;
2. 对Eden+S0进行垃圾收集,存活对象复制到S1。清理Eden+S0。一次新生代GC结束。
(Eden区的对象量达到阈值后,发生一次新生代GC)
3. Eden+S1可分配新生对象;
4. 对Eden+S1进行垃圾收集,存活对象复制到S0。清理Eden+S1。二次新生代GC结束。
5. 循环1。
老生代的mark算法:
标记清除算法
1、将认定为可回收的内存做一个标记
2、统一将被标记的清理
缺点:内存空间碎片化
标记-紧凑算法
在标记-清除算法的基础上,增加了碎片整理这一步,如下图:
1、标记:标记可回收的对象和存活的对象
2、紧凑:将所有存活对象向内存开始部分移动
3、清理被标记为可回收的对象
java垃圾回收方式--垃圾回收器:
应用:
启动时遇到StackOverflowError导致失败的解决办法
在catalina.sh的第二行添加: CATALINA_OPTS="$CATALINA_OPTS -server -Xss100m -XX:+UseG1GC"
串行垃圾回收器:
它为单线程环境设计,只使用一个单独的线程进行垃圾回收,通过冻结所有应用程序线程进行工作,所以可能不适合服务器环境。
它最适合的是简单的命令行程序。
通过JVM参数-XX:+UseSerialGC可以使用串行垃圾回收器。
并行垃圾回收器:
并行垃圾回收器是JVM的默认垃圾回收器。
它使用多线程进行垃圾回收
当执行垃圾回收的时候它也会冻结所有的应用程序线程。
-XX:+UseParallelGC:并行垃圾回收器
G1垃圾回收器:
G1垃圾回收器将堆内存分割成不同的区域,并且并发的对其进行进行垃圾回收。
G1垃圾回收会优先选择第一块垃圾最多的区域,它适用于堆内存很大的情况。
通过JVM参数–XX:+UseG1GC使用G1垃圾回收器