考虑一个java进程,主线程从源读取Json对象,并将具有读取Json对象的任务分配给具有5个工作线程的FixedThreadPoolExecutor。
问题在于,从中读取Jsons的源比工作线程完成任务要快得多。因此,当Jsons在内存中等待工作线程时,会抛出OutOfMemoryException。这里不能增加工作线程数。
以下是OutOfMemory问题的有效解决方案吗?
在主线程中检查可用内存的百分比并在内存使用率超过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);
}
}
有没有好的做法?
答案 0 :(得分:4)
你应该用适当的设计而不是黑客来解决你的OOME问题。您的JSON对象应该被推入一个有界的阻塞队列,这将自动处理对生产者应用“背压”。
更清晰的选择是重新设计,以便为每个提交的任务提供一部分加载的JSON来处理,因此它不会自行提取任何内容。这样您甚至不需要实现队列:您依赖Executor Service内部的队列,您只需要适当地配置它。例如,使用显式ThreadPoolExecutor
构造函数,将CallerRunsPolicy
作为拒绝策略传递给它。
另请注意,提前加载过多的JSON会降低整个系统的速度,因为多余的对象将被提升为旧一代,从而增加主要垃圾收集的频率。
答案 1 :(得分:1)
答案 2 :(得分:1)
不,这不是一个坏主意。据我所知,在发生OutOfMEmoryException之后根本没有指定JVM的行为(抱歉,我现在没有链接)。在某些情况下,您甚至可能看不到此异常。因此,监控JVM堆使用情况至关重要,例如在服务器环境中。
答案 3 :(得分:0)
一个更好的解决方案可能是一个在它满时阻塞的队列。这样,您可以保持积压的可管理性,而不会通过Thread.sleep
进行线程同步。
答案 4 :(得分:0)
我不确定这个想法。主线程从哪里检索其工作?是不是让客户在这2秒内保持睡眠和等待?
我认为你有2种方法可以解决这个问题:
http://www.jafaloo.com/java-xmx-memory-settings/
如果你向他们提供你需要的记忆量的合理估计,那么它们应该是合理的(是的,我在生活中对待过艰难的操作员:P)