From d9d4ef8590b8ad7f49f45413399bb06909aaee04 Mon Sep 17 00:00:00 2001 From: Bernd Ahlers Date: Tue, 20 Jan 2015 15:11:59 +0100 Subject: [PATCH] Create MessagePack singleton provider to avoid PermGen leak. Prepare the MessagePack instance with a RadioMessage because generating code for the MessagePack template registry is not thread-safe. Before this, a new MessagePack instance got created for each processed message which eventually lead to PermGen exhaustion. Not sure why the generated classes haven't been garbage collected. (bug in msgpack?) Fixes #907. --- .../shared/bindings/GenericBindings.java | 10 ++-- .../providers/MessagePackProvider.java | 50 +++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 graylog2-shared/src/main/java/org/graylog2/shared/bindings/providers/MessagePackProvider.java diff --git a/graylog2-shared/src/main/java/org/graylog2/shared/bindings/GenericBindings.java b/graylog2-shared/src/main/java/org/graylog2/shared/bindings/GenericBindings.java index 68f04a00f38a..20ff3b192441 100644 --- a/graylog2-shared/src/main/java/org/graylog2/shared/bindings/GenericBindings.java +++ b/graylog2-shared/src/main/java/org/graylog2/shared/bindings/GenericBindings.java @@ -30,16 +30,18 @@ import org.graylog2.plugin.inputs.MessageInput; import org.graylog2.plugin.inputs.util.ThroughputCounter; import org.graylog2.plugin.system.NodeId; -import org.graylog2.shared.buffers.InputBufferImpl; -import org.graylog2.shared.buffers.ProcessBuffer; -import org.graylog2.shared.buffers.processors.DecodingProcessor; import org.graylog2.shared.bindings.providers.EventBusProvider; +import org.graylog2.shared.bindings.providers.MessagePackProvider; import org.graylog2.shared.bindings.providers.MetricRegistryProvider; import org.graylog2.shared.bindings.providers.NodeIdProvider; import org.graylog2.shared.bindings.providers.ServiceManagerProvider; +import org.graylog2.shared.buffers.InputBufferImpl; +import org.graylog2.shared.buffers.ProcessBuffer; +import org.graylog2.shared.buffers.processors.DecodingProcessor; import org.graylog2.shared.inputs.InputRegistry; import org.graylog2.shared.stats.ThroughputStats; import org.jboss.netty.util.HashedWheelTimer; +import org.msgpack.MessagePack; import java.util.concurrent.Semaphore; @@ -77,5 +79,7 @@ protected void configure() { install(new FactoryModuleBuilder().build(new TypeLiteral>(){})); bind(InputRegistry.class).asEagerSingleton(); + + bind(MessagePack.class).toProvider(MessagePackProvider.class).in(Scopes.SINGLETON); } } diff --git a/graylog2-shared/src/main/java/org/graylog2/shared/bindings/providers/MessagePackProvider.java b/graylog2-shared/src/main/java/org/graylog2/shared/bindings/providers/MessagePackProvider.java new file mode 100644 index 000000000000..c246642a6c6d --- /dev/null +++ b/graylog2-shared/src/main/java/org/graylog2/shared/bindings/providers/MessagePackProvider.java @@ -0,0 +1,50 @@ +/** + * This file is part of Graylog2. + * + * Graylog2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Graylog2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Graylog2. If not, see . + */ + +package org.graylog2.shared.bindings.providers; + +import org.graylog2.plugin.RadioMessage; +import org.msgpack.MessagePack; + +import javax.inject.Provider; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * MessagePack generates classes for each new instance and message type which can leak into PermGen. + * + * Must be a singleton provider! + */ +public class MessagePackProvider implements Provider { + @Override + public MessagePack get() { + final MessagePack messagePack = new MessagePack(); + + try { + // Eagerly generate RadioMessage classes in the MessagePack object to avoid doing it on runtime. + // The generated code is thread-safe, but generating it is not. + final RadioMessage radioMessage = new RadioMessage(); + final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + messagePack.write(stream, radioMessage); + final byte[] bytes = stream.toByteArray(); + messagePack.read(bytes, RadioMessage.class); + } catch (IOException ignore) { + } + + return messagePack; + } +}