JVM垃圾回收机制
如何确定垃圾
1.引用计数法 任何时候只要为0都是可以回收的
2.可达性分析 从gc roots出发到达不了的对象,被标记2次后面临回收
作为GC Roots的对象包括下面几种:
虚拟机栈(栈帧中的本地变量表)中引用的对象。
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)引用的对象。
垃圾回收算法
复制算法:复制,回收,置换
标记整理算法:标记,存活对象移动向一端,清理边界意外的内存
标记清理算法:标记,清除
四种引用类型
强引用 new的对象属于强引用
软引用 oom的时候会被回收
弱引用 gc发生时会被删除
虚引用 幽灵引用,被回收的时候收到一个通知
注意:软引用 SoftReference和弱引用 WeakReference,可以用在内存资源紧张的情况下以及创建不是很重要的数据缓存。当系统内存不足的时候,缓存中的内容是可以被释放的。
例如,一个程序用来处理用户提供的图片。如果将所有图片读入内存,这样虽然可以很快的打开图片,但内存空间使用巨大,一些使用较少的图片浪费内存空间,需要手动从内存中移除。如果每次打开图片都从磁盘文件中读取到内存再显示出来,虽然内存占用较少,但一些经常使用的图片每次打开都要访问磁盘,代价巨大。这个时候就可以用软引用构建缓存。
垃圾收集器
serial:基本垃圾收集器,复制算法,需要暂停其他全部工作线程。成熟,适合单cpu
parnew :serial的多线程版本,复制算法,同样要暂停工作线程,默认是和cpu同等数量的线程数(新生代的默认回收器),停顿时间比上面的少。配合cms最常用。
parallel scavenge:同上。自适应调节策略,不需要指定eden与servivor的比例大小,。
(更关注最大停顿时间或更关注吞吐率。如果不是很清楚如何配置-XX:MaxGCPauseMills,-XX:GCTimeRatio。打开这个就不需要手动配置了-XX:+UseAdaptiveSizePolicy)
serial old:单线程的标记整理算法。经典。jdk默认的。
parallel old:多线程标记整理算法。是parallel scavenge的老年代版本。可以设置吞吐量优先等操作。为了配合parallel scavenge,侧重重视吞吐量的应用。
cms收集器:多线程标记清除算法。初始标记-并发标记-重新标记-并发清除。只有1,3两个阶段需要暂停。所以几乎是并发进行的。存在垃圾浮动时间,需要更大的空间。会有碎片。目前最常用。
G1收集器:标记整理算法,不产生碎片。可以精准的控制停顿时间,不牺牲吞吐率的前途下降低停顿时间。充分利用多核cpu的硬件优势。将堆内存划分成大小固定的几个独立区域,同时维护一个优先级列表。会优先回收满足时间要求的垃圾最多的区域。为了取缔cms。
stop the world
调优的目的就是减少stw现象
新生代配置
新生代大小配置参数的优先级:
高:-XX:NewSize/MaxNewSize
中间 -Xmn (NewSize= MaxNewSize)
低:-XX:NewRatio 表示比例,例如=2,表示 新生代:老年代 = 1:2
-XX:SurvivorRatio 表示Eden和Survivor的比值,
缺省为8 表示 Eden:FromSurvivor:ToSurvivor= 8:1:1
同样的代码情况下:
-Xms20M -Xmx20M -XX:+PrintGCDetails –Xmn2m -XX:SurvivorRatio=2
没有垃圾回收
数组都在老年代
-Xms20M -Xmx20M -XX:+PrintGCDetails -Xmn7m -XX:SurvivorRatio=2
发生了垃圾回收
新生代存了部分数组,老年代也保存了部分数组,发生了晋升现象
-Xms20M -Xmx20M -XX:+PrintGCDetails -Xmn15m -XX:SurvivorRatio=8
新生代可以放下所有的数组
老年代没放
-Xms20M -Xmx20M -XX:+PrintGCDetails -XX:NewRatio=2
发生了垃圾回收
出现了空间分配担保,而且发生了FullGC
full gc触发条件(对整个堆进行垃圾回收)
1 .操作系统调用system.gc()
2.永久代满了
3.大对象直接进入老年代,老年代空间不足
4.Minor GC后,长期存活的对象进入老年代,平均大小大于老年代的可用内存
5.server to大小不够,复制时将数据复制到老年代,且老年代空间不够(空间分配担保)
6.cms,并发标记的过程中。存在垃圾浮动时间。
内存泄漏和内存溢出
内存溢出是空间不够了
内存溢出是该回收的没回收,常见自定义的容器保存元素的情况。
深堆浅堆
举例:对象A引用了C和D,对象B引用了C和E。那么对象A的浅堆大小只是A本身,不含C和D,而A的实际大小为A、C、D三者之和。而A的深堆大小为A与D之和,由于对象C还可以通过对象B访问到,因此不在对象A的深堆范围内。
JDK工具
jps:查看虚拟机进程状态
jstat:监视虚拟机运行状态,监视工具
jinfo:查看和修改虚拟机参数,配置
jmap:生成堆快照,内存映射
jstack:生成线程快照,堆栈跟踪
jconsloe:控制台