考虑一个java进程,因为主线程从源读取Json对象,并将具有读取的Json对象的任务分配给具有5个工作线程的FixedThreadPoolExecutor。
这里的问题是,读取Json的源比工作线程完成任务快得多。因此,当Json在等待工作线程的内存中积累时,就会抛出OutOfMemoryException。这里不能增加工作线程的数量。
那么,以下是解决内存不足问题的有效方法吗?
在主线程中,检查可用内存的百分比,如果内存使用率超过80%,则休眠一段时间
main(){
for(;;){
//read the data and assign to executor
long total = Runtime.getRuntime().maxMemory(),free = Runtime.getRuntime().freeMemory()
float usedPersent = (total-free)*100/total
if(usedPercent > 80)
Thread.sleep(2000);
}
}
有好的练习吗?
您应该用正确的设计而不是黑客来解决OOME问题。您的JSON对象应该被推送到一个有界的阻塞队列中,该队列将自动负责对生产者应用"背压"。
一个更干净的选择是重新设计,这样每个提交的任务都会得到加载的JSON的一部分来处理,这样它就不会自己提取任何东西。这样,您甚至不需要实现队列:您依赖于Executor Service内部的队列,只需要对其进行适当配置即可。例如,使用显式ThreadPoolExecutor
构造函数,将CallerRunsPolicy
作为拒绝策略传递给它。
还要注意,提前加载过多的JSON会降低系统的整体速度,因为多余的对象将被提升到旧一代,从而增加主要垃圾回收的频率。
否-这是个坏主意。
您应该创建具有最大池大小和有限长度队列大小的线程池,并正确处理拒绝。
这里有一个帖子看起来很有希望。它自称是BoundedExecutor
。
不,这是个坏主意。据我所知,JVM的行为只是在发生OutOfMEmoryException之后没有指定(对不起,我现在没有链接)。在某些情况下,您甚至可能看不到这种例外情况。因此,监控JVM堆的使用情况至关重要,例如在服务器环境中。
一个更好的解决方案可能是在队列已满时进行阻塞。这样,您就可以保持积压工作的可管理性,而不会出现通过Thread.sleep
进行线程同步的问题。
我不确定这个想法。你的主线程从哪里检索它的工作?是不是让客户在这两秒钟内保持睡眠和等待?
我认为你有两种方法来解决这个问题:
- 你认为你有什么方法可以提高数据处理的效率吗?也许如果你能让你的工作线程表现得更好,它们就能比目前更快地减轻系统的负载
- 或者,如果您确信无法获得更好的性能,那么您的问题可能是真正的资源问题,应该向您的操作员或管理生产系统的任何人询问不同的JVM设置,使用不同的堆大小。看看
http://www.jafaloo.com/java-xmx-memory-settings/
如果你为他们提供了你需要的内存量的合理估计,他们应该是合理的(是的,我一生中遇到过困难的运算符:p)