jvm垃圾回收
对象存活判断算法
引用计数算法
问题: 可能存在两个对象相互引用,导致无法回收,内存泄漏
根可达算法
维护引用的链表; 如果某个对象无法到达根节点,说明可以被回收
那么哪些对象是根对象呢?主要包含:JVM stack,native method stack,run-time constant pool(运行常量池里的对象),static references in method area(方法区里的静态引用),Clazz等。
垃圾回收算法
对
停顿时间(延时)
和吞吐量
的权衡,没有最好,只有最适合当前业务场景的回收方式
针对 堆内存回收;
方法区
- java 8 前 永久区(也参与垃圾回收,一样的算法,省事了,但是有默认最大内存限制,容易oom)
- java 8 彻底抛弃了 永久区,叫元数据区,使用本地内存
分代收集理论
新生代
老年代
跨代引用: Remember set
标记清除
产生内存碎片,内存分配复杂了。 可能需要类似硬盘的 “分区空闲分配链表” 等复杂方式解决
Cms搜集器在old 区回收时采用, 但是内存碎片达到一定量,会采取一次标记整理。(和稀泥的做法,结合两者,)
标记复制
一般用于新生代回收: Serial ParNew 的新生代采用该算法
scurvivorRadio Ēden survivor survivor 8:1:1
对象存活率较高时,需要更多的复制操作,效率会降低
标记整理
用于old区:
相对于 标记清除, 标记后,需要移动:将存活的对象移动到内存区域的一端。
移动:增大的延迟,stw时间长些,但解决了内存碎片,内存分配复杂的问题,可以提高吞吐量。
不移动:降低了延迟,但内存碎片,内存分配复杂, 吞吐量有所下降。
垃圾回收器
对于新生代一般时使用标记复制算法
对于老年代一般使用标记整理算法 (CMS除外)
Serial收集器
- 串行
ParNew收集器
- 并行
Parallel Scavenge收集器
-XX:+UseParallelGC -XX:+UseParallelOldGC
调整方式
1.手动调整 -Xmn -Xms -XX:NewRatio=N 手动指定堆内存大小和代空间比例,一般要多次试验 2.自动参数调整 -XX:MaxGCPauseMillis=N 可接受最大停顿时间 -XX:GCTimeRatio=N 可接受GC时间占比(目标吞吐量) 吞吐量=1-1/(1+N)
并行
尽可能可以控制吞吐量 也叫 吞吐量优先收集器
-XX:+UseAdaptiveSizePolicy 默认开启的
Serial Old收集器
用于old区:串行
Parallel Old收集器
用于old区:并行
CMS收集器
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
尽可能缩短垃圾回收时,用户线程的停顿时间
和ParNew收集器配合:
Garbage First (G1)收集器
内存分配与回收策略
对象优先在Edem区分配
大对象直接进入老年代
长期存活的对象进入老年代
每个对象有个
年龄计数器
MinorGC一次,加1-XX:MaxTenuringThreshold=X X默认是15, 15次后进入老年代
动态对象年龄判断
-XX:TargetSurvivorRatio 目标存活率,默认为50%
survivor中相同年龄的对象大小之和大于TargetSurvivorRatio后,大于等于该年龄的都晋升到老年代。
空间分配担保
相关应用
查看当前java版本使用的GC
java -XX:+PrintCommandLineFlags -version
[root@sd01 ~]# java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=128167296 -XX:MaxHeapSize=2050676736 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
UseParallelGC 按道理时使用 Parallel Scavenge + SerialOld,但后来P araller old出现后,实际默认时用的
Parallel Scavenge + Parallel Old
默认堆大小
什么是jdk1.8默认堆大小? (MaxHeapSize)
就是使用java -jar 并且没有手动指定-Xmx参数的启动的进程使用的堆的大小,就是用的默认jdk堆的大小。
这个默认的堆大小是取决你服务器的物理内存,假如服务器内存大于1GB,则使用1/4的服务器物理内存作为jvm的堆内存大小。
eg:服务器内存4GB 则默认堆大小为1GB
java -XX:+PrintFlagsInitial
配置试例
java -Xms1600m -Xmx1600m -Xmn800m -Xloggc:/xxx/logs/xxx_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=20 -XX:GCLogFileSize=100M -Dprofile=prod -jar /xxx/xxx-1.0.0-SNAPSHOT.jar
-Xms: //堆内存初始化大小 -Xmx: //堆最大可用内存 -Xmn: //新生代堆最大可用内存 -XX:UseParallelGC //使用gc的类型
-XX:SurvivorRadio//设置新生代中:Eden空间、SurvivorRadio From空间、SurvivorRadio To空间的占比 -XX:NewRatio //设置新生代空间和老年代空间的占比 -XX:+PrintGC //每次触发GC的时候打印相关日志 -XX:+PrintGCDetails //打印详细Gc日志
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles
-XX:GCLogFileSize