Springframework';s InvocableHandlerMethod.GetMethodArgumentValue占用大量cpu
我有一个用java和Spring4.0编写的web应用程序,部署在tomcat(RedHatLinux)上。在使用JProfiler评测我们的webapp时,我们发现大部分时间都花在Springframework中,这导致了API的速度减慢。例如,考虑下面提到的数据,显示在614秒内,在Spring中花了609秒,这是用于105个API调用,这意味着每个API调用的时间是6秒。 所以我想知道spring中是否有可以避免这种开销的配置 编辑:添加我使用JProfiler获得的更多数据Springframework';s InvocableHandlerMethod.GetMethodArgumentValue占用大量cpu,spring,Spring,我有一个用java和Spring4.0编写的web应用程序,部署在tomcat(RedHatLinux)上。在使用JProfiler评测我们的webapp时,我们发现大部分时间都花在Springframework中,这导致了API的速度减慢。例如,考虑下面提到的数据,显示在614秒内,在Spring中花了609秒,这是用于105个API调用,这意味着每个API调用的时间是6秒。 所以我想知道spring中是否有可以避免这种开销的配置 编辑:添加我使用JProfiler获得的更多数据 91.0
91.0% - 614 s org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest
90.2% - 609 s org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues
55.9% - 377 s org.springframework.validation.DataBinder.convertIfNecessary
34.2% - 231 s org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.resolveName
0.8% - 5,709 ms org.springframework.web.method.support.InvocableHandlerMethod.invoke
编辑:
进一步深入研究后,我发现,在这90.2%的时间中,有88%被以下两种方法消耗
org.springframework.util.ConcurrentReferenceHashMap.put
org.springframework.util.ConcurrentReferenceHashMap.get
而且他们是从
org.springframework.core.ResolvableType.forType
有人在linux和Spring应用程序上也观察到了这一点吗
仅供参考我的控制器方法有23个查询参数,其中9个是列表,这会产生任何问题吗?我不应该有这么多的查询参数(@RequestParam)?
park
不会执行繁忙的等待。实际上,它甚至不知道线程正在等待的条件。这取决于打电话的人。但是,如果经常调用park
,例如调用了unpark
,但在重新检查等待条件后,会再次调用park
,则仍然会消耗大量CPU。然后,park
的固定开销将累积
因此,这里的情况似乎是,您在某个特定锁上存在严重的争用。从您发布的堆栈跟踪中,我猜
ConcurrentReferenceHashMap
配置的并发级别远远小于您的实际线程数。似乎是自定义参数解析器完成了这一任务。如中所述创建一个后
jprofiler计时很好,而且我的customArgumentResolver消耗的CPU没有HandlerMethodArgumentResolverComposite.resolveArgument多 他在做什么
现在额外的90.2%的时间减少到了2%(10秒)我同意,这就是我在问题中观察到和写的,调用方方法java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued循环并一次又一次调用park,直到成功,所以它的acquireQueued正在进行繁忙等待。将问题标题更改为具有误导性。Thanks@Rahul:但AQS不执行“忙等待”,因为它调用
park
park
将释放CPU。但据我所知,os_linux.cpp中的park实现不会释放CPU,因为它使用的是pthread_mutex_trylock(mutex),如果失败(因为其他人已经获得了该互斥体),它将立即从那里返回,AQS将在其for(;)中再次调用park环下面是代码段//如果无法获得锁,请不要等待,因为取消阻止会产生干扰。也。如果(Thread::is_interrupted(Thread,false)| | pthread_mutex_trylock(_mutex)!=0){return;}只有在另一个线程同时调用unpark
时才会发生这种情况,请在尝试等待之前检查中断。但无论如何,你看错地方了。如前所述,重要的不是park
的实现,而是这么多线程都在争夺同一个锁。