由于使用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次数就大大减少了。
分享到:
相关推荐
在IT领域,尤其是Java应用服务器环境中,Tomcat作为一款广泛使用的开源轻量级Web服务器,其在处理高负载或大流量请求时,可能会遭遇内存不足的问题,即所谓的“Out of Memory Error”。这通常表现为两种主要类型:...
1. 增加物理内存:为了提高性能,可以在Boot.ini文件中启用/3GB开关,让SQL Server使用超过2GB的物理内存。不过,需要了解如何配置SQL Server以利用这个开关,可以参考微软知识库的相关文章。 2. 调整执行时间:将...
如果应用加载大量类或者使用SSH2等框架导致动态类生成,可能会超出默认大小,引发`Out of MemoryError: PermGen space`。 解决 PermGen Space溢出的方法: 1. **减少重复jar文件**:将相同的第三方jar移动到Tomcat...
- **内存配置**:合理分配JVM堆内存,避免Out of Memory错误。 - **启用GZIP压缩**:减少网络传输数据量,提高响应速度。 - **日志管理**:限制日志级别,避免不必要的性能消耗。 4. **安全性** - **SSL/TLS...
如果遇到“Out of memory”错误,应启用“详细垃圾回收”,以便分析内存使用情况。HeapDump文件通常位于`IBM/WebSphere/AppServer/profiles/`目录下,可用于进一步的内存分析。 #### 二、TCP传输通道调整 TCP传输...
总结而言,优化Tomcat的内存设置,尤其是 PermGen space 和Heap大小,是避免“Out of Memory”错误的关键。通过对JVM参数的细致调整,可以确保Web应用在高负载下稳定运行,提升整体性能。同时,合理组织应用的类加载...
2. **最大堆大小(Xmx)**:限制JVM可以使用的最大内存,防止因内存不足导致的"Out of Memory"错误。 3. **新生代大小(NewSize或XX:NewRatio)**:新生代内存大小会影响垃圾收集的频率和效率,通常新生代与老年代的...
- 如果遇到“Out of memory”错误,可以通过开启“详细垃圾回收”功能来进行内存分析。 #### 三、TCP传输通道调整 TCP传输通道决定了客户端与服务器之间的连接数量,直接影响了系统的并发处理能力。调整步骤如下...
理解这些内存区域的工作原理对于避免OOM(Out of Memory)错误至关重要。 - 堆内存:存放对象实例,进行垃圾回收。 - 栈内存:每个线程都有独立的栈,存储方法调用的状态。 - 方法区(永久代/元空间):存储类...
4. **内存溢出(Out of Memory)** - 错误描述:日志中出现“java.lang.OutOfMemoryError”。 - 原因分析:Java堆内存不足,处理大量数据或长时间运行的应用可能导致此问题。 - 解决方案:增大JVM的内存分配,...
当Tomcat运行时,如果内存分配不当,可能会出现“Out of Memory”错误,比如“gen space不够”的报错,通常指的是新生代内存不足。为避免这类问题,我们需要在启动Tomcat时指定适当的内存参数。 在Eclipse中设置...
3. **内存不足**:如果MyEclipse或Tomcat启动时出现内存溢出错误(Out of Memory),则可能需要增加JVM的堆大小。这可以通过修改MyEclipse的运行配置或Tomcat的bin/startup.bat/sh文件中的JAVA_OPTS变量来实现。 4....
首先,让我们详细讨论`PermGen space`。 PermGen(Permanent Generation)是Java虚拟机(JVM)的一个内存区域,主要用于存储类的元数据,如类的名称、方法信息等。与堆区不同,堆区中的对象在不再被引用时会被垃圾...
内存溢出(Out of Memory)是指程序在运行过程中申请的内存超过了系统能提供的最大内存限制时,程序会抛出异常,导致应用崩溃或者无法正常运行。这种现象在Java等面向对象的编程语言中较为常见。 #### 知识点二:...
9.4.6. Working with Fractions of Seconds 9.4.7. Sunrise / Sunset 9.5. Creation of dates 9.5.1. Create the actual date 9.5.2. Create a date from database 9.5.3. Create dates from an array 9.6. ...
- **OutOfMemory**:内存溢出错误。 - **StackOverflow**:栈溢出错误。 #### 九、JVM原理与调优 JVM的参数设置对于程序性能有着直接影响。常见的参数包括: - **Xms/Xmx/Xmn**:设置堆空间的初始大小、最大大小...
- OOM(Out Of Memory):内存溢出。 - SOE(StackOverflowError):栈溢出。 - **GC(Garbage Collection)算法** - 包括标记-清除、复制、标记-压缩等算法。 - **JVM监控工具** - 如jps、jstat、jmap、jinfo...
You can also view the system information that has been retrieved—such as CPU, memory, and processes running on the machine—and an image of the machine executing the system test. 6、测试用例设计、...