但是使用System.gc()可以直接释放掉内存,因为创建的StringBuffer还是一个对象,可以被垃圾回收,当其被垃圾回收的时候,就会调用一个clean方法,然后里面调用unsafe.freeMemory
直接内存通过unsafe释放内存
ByteBuffer使用直接内存
看内存占用情况,看任务管理器
性能调优问题
因为需要显式的调用垃圾回收,在代码中加入System.gc()这段代码是不好的,因为是显式的垃圾回收(Full GC),所以为了增加性能在虚拟机参数中使用-XX:+DisableExplicitGC 将在代码中加入的垃圾回收都注释掉,意思是不起作用,但是这又影响直接内存可能要等很长时间才会自动触发垃圾回收从而调用freeMemroy释放直接内存,所有在这种情况下可以使用unsafe直接对直接内存进行管理,手动free
垃圾回收器
吞吐量优先
多线程
适用于:堆内存较大,多核cpu
优点:让单位时间内,STW的时间最短 0.2 0.2 = 0.4 (一个小时垃圾回收时间)
响应时间优先
多线程
适用于:堆内存较大,多核cpu
优点:STW(世界暂停)尽可能让单次的STW的时间最短 0.1 0.1 0.1 0.1 0.1 = 0.5(一个小时执行5次,每次0.1)
串行
新生代使用复制算法,老年代采用标记整理算法
吞吐量优先
在1.8下默认用的这个,新生代使用复制算法,老年代采用标记整理算法,算法上和串行的垃圾回收器时一样的,不会产生碎片,但是区别时垃圾回收器是并行的,回收器和cpu核数相关,有多少个就多少个回收器,ratio默认19,0.05==5%的垃圾回收时间
响应时间优先CMS
对应用程序的吞吐量有影响,因为占用了一个cpu核,只有原来的3/4
并发运行,用户线程也能工作,某些时刻不用STW,新生代使用复制算法,老年代使用标记删除算法(并发运行),老年代可能会发生并发失败,老年代退化为单线程SerialOld(标记整理算法)
如果后续标记删除失败,那么退化为串行,那么将会使用更多的时间
第四个参数是在remark之前再做一次新生代垃圾回收,因为通过新生代对象找老年代对象,然后找根对象,这也有些新生代对象本身就是垃圾,那么这部分工作就没用了,所以先对新生代对象进行垃圾回收,再进行remark,节省时间
G1
jdk9已经废弃了CMS垃圾回收器
选择性地复制一些老年代地对象(选择所占内存最高的,最有效益的),因为需要达到一定的吞吐量,为了达到这个目的,因为复制对象需要占用很长的时间,优先收集垃圾最多的区域(老年代)
Full GC
当CMS和G1的并发标记阶段,垃圾回收的效率高于程序运行产生的垃圾,那么此时的并发标记是成功的,不会退化到串行回收器,那么就不会出现full gc,当回收的速度跟不上垃圾产生的速度的时候(对空间被占满),那么就会垃圾回收器就会退化到串行状态会触发full gc,full gc的速度就很慢了
图片来源:bilbili黑马程序员,侵权联系我删除