当前位置: 首页 > 知识库问答 >
问题:

ConcurrentLinkedQueue$Node 实例增长,JVM 抛出 OOM

魏旭
2023-03-14

我在生产者-消费者场景中使用 ConcurrentLinkedQueue。我的生产者是一个由我的应用程序中的所有方法调用的单例:Producer.getInstance().add(“foo”);add() 方法调用 ConcurrentLinkedQueue offer 方法。

public void add(String message) {
    myQueue.offer(message);
}

否则,我会让我的消费者在另一个线程中运行,并简单地在生产者内部的并发链接队列上调用轮询方法。

编辑:

在if((缓冲区=myQueue.poll ()) ! = 空){}之间添加代码

CRActiveMQProducer是一个单例,它初始化与我的ActiveMQ服务器的连接并使用send()方法发送消息。

private StringBuffer stringBuffer = new StringBuffer();

public void run() {
    while(condition) {
        String buffer = null;
        if ((buffer = myQueue.poll()) != null) {
            stringBuffer.append(buffer);
            numberMessage++;
            if (numberMessage >= 10000) {
                CRActiveMQProducer.getInstance().send(stringBuffer.toString());
                stringBuffer = stringBuffer.delete(0, stringBuffer.length());
                numberMessage = 0L;
            }
        }
    }
} 

我调用 Producer add() 方法就像 5000 万次一样(是的,它很大,但它只是应该完成的调用数量的 2,5%)

无论如何,我得到了一个OutOfMemory异常,我尝试用VisualVM读取堆转储,我发现这个OOM是由大量的ConcurrentLinkedQueue$Node实例(超过3000万个)引起的。我想我对每个offer()或poll()方法调用都有一个新的节点,但不是100%确定(不能加载完整的堆转储...).

您认为这是ConcurrentLinkedQueue的正常行为吗?还是我做错了什么?谢谢

共有2个答案

甄云
2023-03-14

几个建议:

    < li >为您的应用程序添加更多内存。尝试类似于< code>-Xmx2g的内容 < li >尝试添加额外的线程以从队列中读取数据 < li >尽快完成“使用缓冲区做点什么” < li >将“用缓冲区做点什么”剥离到它自己的线程中(可能使用线程池),以防止它阻塞从队列中读取更多内容

你有没有对读者服务中的所有内容进行计时,看看需要多长时间?如果你真的把东西放在队列上的速度快于你能读完的速度,那么你就需要找到加快读取器速度的方法。你的记忆力不足只是真正问题的副作用。问题是你处理排队工作的速度不够快。

逑禄
2023-03-14

队列显然必须存储你放在队列中的所有元素,它使用相互链接的节点来做到这一点。这就是链接队列的原则。你的生产者生产itels太快了,消费者没有时间消费它们,所以最终,你得到了一个OOM。

您应该考虑使用绑定的BlockingQueue:当队列包含太多元素时,它会强制生产者线程阻塞,从而避免OOM。

 类似资料:
  • node-jvm 实现了纯 Node.js 环境下的 Java 虚拟机。 示例: java public class Main { public static long fib(int n) { if (n <= 1) return n; return fib(n-1) + fib(n-2); } public static void main(Str

  • 我使用了Maven LibSVM版本1.0.6(链接) 如果在创建模型之前设置setProbabilityEstimates(true),那么在尝试对新实例进行分类时会得到NullPointerException。 我的代码: 异常堆栈跟踪: 在太阳下。反映NativeMethodAccessorImpl。在sun上调用0(本机方法)。反映NativeMethodAccessorImpl。在sun

  • 我知道JVM有一个异常表,它映射在给定字节码索引中可以抛出的可能异常。我还读到athrow字节码抛出了堆栈顶部存在的引用类型的exception。我的问题更多地涉及像irem这样的指令如何“抛出”异常。 JVM是否会在每次指令执行后检查堆栈的顶部,以检查是否存在异常?如果你能洞察到这件事的话,你会很感激的。

  • 我有一个系统,其中许多线程产生的日志将被插入到一个NoSql后端。为了减少网络流量,我在服务器和后端之间引入了一个缓冲区。 环境是: Java,JSP,Spring MVC,JDK 1.7 Apache-tomcat-6 使用的缓冲区是java中的ConcurrentLinkedQueue。还实现了一个DBPushThread来每5秒从队列中获取日志,并将它们插入backened。我们使用offe

  • 我有一个AWS DynamoDb表,它是写密集型的。我已经在预配容量模式下配置了WCU和RCU。 我正在使用AWS数据管道将DynamoDb内容导出到S3。管道配置为读取吞吐量比率。 在这个设置中导出150GB的数据需要大约2个小时。当我将RCU增加到时,导出在不到20分钟内完成。 在DataPipeline中是否有任何方法仅在管道运行时增加预配的RCU?由于此管道配置为每天仅运行一次。

  • 下面是一些使用的JVM标志, -xmx3500m -XMS3500M -xx:maxmetaspacesize=400m -xx:compressedclassspacesize=35m 注意:线程堆栈的大小(1MB)和代码缓存(240MB)是默认的,JDK版本是1.8.0_252。 甚至由“jcmd pid vm.native_memory summary”输出产生的总和也是5.0GB,甚至不是