资料引用:http://www.knowsky.com/362375.html
内存(条)是便宜,很不幸,垃圾回收机制导致的暂停会严重影响系统性能,好像JVM内存最多支持2G,作者花费大量时间精力使用32G来提高系统性能,这篇是其心得。GC微调是非常和应用有关,该篇的目标要求是:使用10G更大Heaps和严格的响应时间(毫秒级别),(吞吐量和延迟性是一对矛盾,这次GC微调主要是追求低延迟)。作者项目特点是:
1.Heap用于在内存中储存数据结构
2.Heap大小超过10G
3.请求时间要求更快
4.事务是短的(几百毫秒) 一个事务可以包括几个请求
5.内存中数据修改频率和面积低,不会一秒内修改整个10G内存,每秒更新10M即咐余可。
此处省略垃圾回收机制原理介绍.....
总体来说,banq注:JVM分新生代和旧生代,新创建在新生代,通过新生代垃圾回收,如果不能被回收,将逐步转入旧生代,旧生代内存可以实现缓存In-memeory数据,显然新旧两代的垃圾回收算法最好不一样,新生代需要频繁,而旧生代不需要频繁,如果我们内存缓存控制得好,旧生代就不会启动垃圾回收机制,这样就不会导致系统暂停。
该文介绍如何来进行新生代大小调节,防止垃圾回收机制频繁启动,先使用XX:MaxNewSize= -XX:NewSize= 指定新生代大小,使用-XX:+PrintGCDetails -XX:+PrintTenuringDistribution -XX:+PrintGCTimestamps)输出GC诊断结果。
有几个数据需要计算一下:
新生代收集期间值,整个分配情况,短生命对象的分配大小,长生命对象的分配情况,中等生命对象分配。
我个人更喜欢使用psi-Probe安装在tomcat下,一目了然,如附件图:
配置恰当的缓存Cache策略来解决GC问题也相当重要,我们提倡基于内存的领域对象编程,大量数据都在缓存中in-memory,如何衡唯滚保证他们的生命周期和JVM的垃圾回收机制不冲突,也是一种实际问题,文章提出下面几点:
1.为缓存增加失效期,让新生代的GC期间要长于缓存的失效期,也就是缓存中对象数据失效后,正好GC启动后可以回收这些失效对象。
2.增加延长新生代的GC期间。
3.在缓存中使用弱引用。缓存产品自己的事,和我们应用者无关。
4.增加缓存大小,我个人经验尽可能将数据库数据以领域对象方式都加载到内存中。
JVM首先分配所有对在新生代,然后将幸存对象(一般是缓存中对象)再分配到旧生代,或再分配到新生代,这些对象的拷贝将耗费时间导致新生代收集暂停,两种选择:
1.在第一次收集时,就将对象复制到旧生代
2.第二次收集时,将对象复制到旧生代。
第一种办法将导致一些短生命周期对象复制到旧生代,第二种办法需要注意新生代垃圾收集的频度和长生命周期对象是否小。
对于一个巨大的heap,新生代垃圾收集暂停主要是在空间扫描和复制幸存对象上,在新生代大小上需要取得一个平衡,旧生代大小足够放入应用的数据,比如JiveJdon一天下来缓存的大小是200K左右(每天启动的情况下),山升只要旧生代大小大于这个值即可,不能太大,也不能太小。
增加新生代大小要增加整个JVM大小,否则就会降低旧生代的内存大小。
可以配置CMS短期暂停:–XX:CMSWaitDuration –设置收集暂停的最大间隔时间,越大你的应用将被暂停,类似死机没有反应。XX:+CMSScavengeBeforeRemark 可以避免在收集期间同时扫描。
原文还提到CMS(Concurrent Mark Sweep)激活会导致暂停等等。
针对不同应用特点进行算法配置,在线事务处理将耗费响应时间,而批处理将产生大量垃圾,这些都要用不同JVM来处理。
System.gc()是“呼叫”垃圾回收器回收垃圾的,这么说不太严谨,其实但是只是“通知”而已,具体回收不回收由垃圾收集器的算法决定,你完全可以开发一个什么也不干的垃圾收集器,或者激此等内存被占用超过一定比例再回收判祥的垃圾收集器。finalize()方法是明冲迅一个类对象在销毁时会被调用的方法,垃圾收集器在发现这个类对象不会再被使用时就会回收内存,也就是销毁该对象,从而finalize()被调用了。你这个程序System.gc()是最后一句,显然前一句创建的Book对象后面不会被使用了,所以JDK带的垃圾回收算法就会调用该对象的销毁方法来回收了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)