由于使用Jetty+Jersey做为RESTful server,由于用户通过REST API访问后台服务时,单个用户一次提交或者取得的数据最大值为50M,假设jvm的heap size最大值为1G的话,如果并发的用户数过多,后台就很可能出现outofmemory的error。为了避免这种情形发生,想出了一个初步方案:
1 配置一个filter,并每个用户请求都会经由filter的filter方法处理
2 每次filter方法调用的,都会检查jvm的heap memory的使用情况,如果heap memory使用率到达了80%以上,则调用System.gc(),并拒绝访问,返回503错误,告知client端。
代码如下:
private void checkServerMemoryUsage() {
MemoryMXBean aMemoryMXBean=ManagementFactory.getMemoryMXBean();
MemoryUsage heapMemoryUsage=aMemoryMXBean.getHeapMemoryUsage();
long usedHeapMemory = heapMemoryUsage.getUsed();
long maxHeapMemory = heapMemoryUsage.getMax();
double MemUsedRate = (usedHeapMemory*1.0)/maxHeapMemory;
if(MemUsedRate >= 0.8) {
System.gc();
logger.error("Heap memory will be expired. Used Memory is: "+maxHeapMemory+" bytes. The max heap memory is: "+maxHeapMemory+" bytes.");
throw new RestException(503, "Server is too busy!");
}
}
本来以为这样没问题了,可是后来在调试的过程中发现这样一个现象:
模拟10个客户端,同时向server发请求,每个客户端每次提交的数据为5M,每个客户端连续发5000次,运行过程中把-verbosegc选项打开,开始时,情况很正常,gc动作经常进行(这是由于新生代的Eden区域经常满的缘故,触发了minor GC),由于后台还会把用户提交的数据进行负责处理,也会产生很多新的对象,所以堆的已用区越来越大,但使用率到达80%的时候,显式的调用了System.gc(),这时候系统会执行次full gc,并且客户端也会收到503错误。一切看起来比较完美。
当我把所有客户端线程都kill掉的时候,问题来了,heap的占用率还在缓慢增长(因为前面提交的数据可能还在处理),但是minor gc并不触发了(Eden区域未满就不会触发),可见大量的对象在年老代区(Old generation),而年老代又没有被写满,不会被触发full gc(默认配置是1小时才会定时执行一次full gc),这时候heap已用率会长期维持在高位。
于是一个改进方案出现了:
写道
static class MemoryInfo{
long usedHeapMemory;
long maxHeapMemory;
double getUsageRate(){
return (usedHeapMemory*1.0)/maxHeapMemory;
}
}
private void checkServerMemoryUsage() {
MemoryInfo info = getHeapUssageRate();
if(info.getUsageRate() >= 0.8) {
System.gc();
info = getHeapUssageRate();
if(info.getUsageRate() >= 0.8) {
logger.error("Heap memory will be expired. Used Memory is: "+info.usedHeapMemory+" bytes. The max heap memory is: "+info.maxHeapMemory+" bytes.");
throw new RestException(503, "Server is too busy!");
}
}
}
private MemoryInfo getHeapUssageRate() {
MemoryInfo info = new MemoryInfo();
MemoryMXBean aMemoryMXBean=ManagementFactory.getMemoryMXBean();
MemoryUsage heapMemoryUsage=aMemoryMXBean.getHeapMemoryUsage();
info.usedHeapMemory = heapMemoryUsage.getUsed();
info.maxHeapMemory = heapMemoryUsage.getMax();
return info;
}
每次请求来的时候,检查heap使用情况,如果使用率到达80%了,马上调用Sytem.gc()执行full gc。然后再次判断看使用率是否超过80%,如果还是超过的话,则拒绝服务,返回503错误。
进一步改进:
因为full gc会耗时较长,经常调用会影响服务器的性能(调用时别的线程会被挂起)。分析应用情况,发现临时数据缓存占内存占用的大多数,这样调大server的jvm的新生代在堆中的比例,这样只会让minor gc调用比较频繁,而由System.gc()引发的full gc次数就大大减少了。
分享到:
相关推荐
解决Out of memory问题,玩游戏的童鞋遇到的问题,希望能帮到那些遇到此类问题的童鞋
tomcat out of memory,近来web经常out of memory down机,查找的一些资料
Out of memory-cannot load design mode
java OutOfMemory的一个解决方法
Out of memory,insufficient memory to continue.
一次奇怪的Out of Memory 分析(附图)
最近在跑程序,然后Pycharm就跳出out of memory 的错误提示,可能是由于读取的数据太多导致的,Pycharm有一个默认内存的最大容量上线,跳出提示的是1024M,也就是分配给Pycharm的内内存不够啦! 一、说明: pycharm...
NULL 博文链接:https://keren021.iteye.com/blog/1163165
tomcat out of memory solution
android bitmap outofMemory 用来解决android中常见的bitmap outOfMemory
NULL 博文链接:https://boyseegirl.iteye.com/blog/1729527
Out of memory (Needed 16777224 bytes)的错误解决 看看手册: [url]http://dev.mysql.com/doc/refman/5.1/en/memory-storage-engine.html[/url] 开始我更改了query_cache_size的值。 好像也不行。 之后 增大query_...
今天发现网站有点慢,发现mysql日志中提示mysqld-nt: Out of memory (Needed 1677720 bytes),经排查是由于最近调整了mysql的一些参数导致,以为内存大就不怕了,32位系统真心内容利用率很低,据说不超过4G,我们的...
今天小编就为大家分享一篇解决Python运行文件出现out of memory框的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
最近公司将内部使用的代码由svn迁到了git上,所以也必须学者使用Git命令。 虽说git的模式和svn区别很大,但想必也不是什么难事。...fatal: Out of memory, malloc failed (tried to allocate 1941159936 b
out of memory是什么意思.docx
今天小编就为大家分享一篇Pytorch GPU显存充足却显示out of memory的解决方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
主要为大家详细介绍了Android避免内存溢出Out of Memory方法汇总,具有一定的参考价值,感兴趣的小伙伴们可以参考一下