From 68c29c4c548211a680f492e81e2ad28e07989cec Mon Sep 17 00:00:00 2001 From: leventov Date: Sat, 5 Nov 2016 14:40:42 -0600 Subject: [PATCH] Use on-heap elastic bytes in DataAccess implementation in order not to pollute direct memery with small allocations, reallocations and associated Cleaners, when many ChronicleMaps are created in the JVM. Also, NativeBytes reallocation granularity is 4KB, that is too much for likely small keys and values. --- .../AbstractCharSequenceUtf8DataAccess.java | 2 +- .../impl/BytesMarshallableDataAccess.java | 2 +- .../impl/DefaultElasticBytes.java | 29 +++++++++++++++++++ .../ExternalBytesMarshallableDataAccess.java | 2 +- .../impl/SerializableDataAccess.java | 2 +- .../impl/SizedMarshallableDataAccess.java | 2 +- .../serialization/impl/ValueDataAccess.java | 18 ++++++++---- 7 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 src/main/java/net/openhft/chronicle/hash/serialization/impl/DefaultElasticBytes.java diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/AbstractCharSequenceUtf8DataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/AbstractCharSequenceUtf8DataAccess.java index 7b928b793..cea2023fa 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/AbstractCharSequenceUtf8DataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/AbstractCharSequenceUtf8DataAccess.java @@ -41,7 +41,7 @@ abstract class AbstractCharSequenceUtf8DataAccess extend } private void initTransients() { - bytes = Bytes.allocateElasticDirect(1); + bytes = DefaultElasticBytes.allocateDefaultElasticBytes(); } @Override diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesMarshallableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesMarshallableDataAccess.java index a2bb0098d..4aec10627 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesMarshallableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/BytesMarshallableDataAccess.java @@ -47,7 +47,7 @@ public class BytesMarshallableDataAccess } private void initTransients() { - bytes = Bytes.allocateElasticDirect(1); + bytes = DefaultElasticBytes.allocateDefaultElasticBytes(); targetBytes = VanillaBytes.vanillaBytes(); } diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/DefaultElasticBytes.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/DefaultElasticBytes.java new file mode 100644 index 000000000..c20fe3079 --- /dev/null +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/DefaultElasticBytes.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2012, 2016 higherfrequencytrading.com + * Copyright (C) 2016 Roman Leventov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * This program 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package net.openhft.chronicle.hash.serialization.impl; + +import net.openhft.chronicle.bytes.Bytes; + +final class DefaultElasticBytes { + + public static Bytes allocateDefaultElasticBytes() { + return Bytes.elasticHeapByteBuffer(32); + } + + private DefaultElasticBytes() {} +} diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalBytesMarshallableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalBytesMarshallableDataAccess.java index 3ef754b77..508d8636b 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalBytesMarshallableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/ExternalBytesMarshallableDataAccess.java @@ -52,7 +52,7 @@ public class ExternalBytesMarshallableDataAccess extends InstanceCreatingMars } private void initTransients() { - bytes = Bytes.allocateElasticDirect(1); + bytes = DefaultElasticBytes.allocateDefaultElasticBytes(); } @Override diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/SerializableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/SerializableDataAccess.java index e03b84d05..50747b875 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/SerializableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/SerializableDataAccess.java @@ -45,7 +45,7 @@ public class SerializableDataAccess extends AbstractData } void initTransients() { - bytes = Bytes.allocateElasticDirect(1); + bytes = DefaultElasticBytes.allocateDefaultElasticBytes(); out = bytes.outputStream(); in = bytes.inputStream(); } diff --git a/src/main/java/net/openhft/chronicle/hash/serialization/impl/SizedMarshallableDataAccess.java b/src/main/java/net/openhft/chronicle/hash/serialization/impl/SizedMarshallableDataAccess.java index a7b14c8bd..31515db27 100644 --- a/src/main/java/net/openhft/chronicle/hash/serialization/impl/SizedMarshallableDataAccess.java +++ b/src/main/java/net/openhft/chronicle/hash/serialization/impl/SizedMarshallableDataAccess.java @@ -62,7 +62,7 @@ public class SizedMarshallableDataAccess extends InstanceCreatingMarshaller extends AbstractData implements DataAccess { @@ -68,8 +68,16 @@ public class ValueDataAccess extends AbstractData implements DataAccess nativeInstanceAsCopyable = (Copyable) nativeInstance; nativeClass = (Class) nativeInstance.getClass(); heapClass = Values.heapClassFor(valueType); - nativeInstance.bytesStore(nativeStoreWithFixedCapacity(nativeInstance.maxSize()), - 0, nativeInstance.maxSize()); + nativeInstance.bytesStore(allocateBytesStoreForInstance(), 0, nativeInstance.maxSize()); + } + + private BytesStore allocateBytesStoreForInstance() { + long instanceSize = nativeInstance.maxSize(); + if (instanceSize > Bytes.MAX_BYTE_BUFFER_CAPACITY) { + return NativeBytesStore.nativeStoreWithFixedCapacity(instanceSize); + } else { + return BytesStore.wrap(ByteBuffer.allocate(Maths.toUInt31(instanceSize))); + } } protected T createInstance() {