Subject Re: [Firebird-Java] Possible memory leak in EncodingFactory ?
Author Roman Rokytskyy
> Can you send me a diff? I'm curious how removing the working buffer
> slowed it down that much, primitive memory allocation isn't that bad in
> Java.

That's what I thought some time ago... I have managed to slow down Jaybird
twice by doing new byte[16384] in each operation (I wanted to ensure that
the communication buffer is not overwritten - I was looking for a bug and
that was the easiest solution to that problem). It took me few days in
profiler until I found the reason.

> Also it should have removed the need for one buffer. What JVM were you
> using?

Sun 1.4.2 - the one I use to build official releases.

The other thing wonders me more - the Encoding classes were not cached in
previous case, so I doubt that it reused the buffer a lot. It looks like
memory allocation during class instantiation (or with the constant length)
is less expensive than dynamic memory allocation...


The diff:

Index: EncodingFactory.java
===================================================================
RCS file:
/cvsroot/firebird/client-java/src/main/org/firebirdsql/encodings/EncodingFactory.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -r1.13 -r1.14
27a28,29
> public static final boolean USE_ENCODING_CACHING =
> Boolean.getBoolean("jaybird.encoding.cache");
>
116a119
> private static HashMap mainCache = new HashMap();
117a121,132
> if (USE_ENCODING_CACHING) {
> Encoding result = (Encoding)mainCache.get(encoding);
> if (result == null) {
> result = createEncodingInternal(encoding);
> mainCache.put(encoding, result);
> }
> return result;
> } else
> return createEncodingInternal(encoding);
> }
>
> public static Encoding createEncodingInternal(String encoding) {
214a230,231
> private static HashMap translatorCache = new HashMap();
>
215a233,245
> if (USE_ENCODING_CACHING) {
> Encoding result = (Encoding)translatorCache.get(encoding);
>
> if (result == null) {
> result = getEncodingInternal(encoding, charMapping);
> translatorCache.put(encoding, charMapping);
> }
>
> return result;
> } else
> return getEncodingInternal(encoding, charMapping);
> }
> public static Encoding getEncodingInternal(String encoding, char[]
> charMapping){
Index: Encoding_OneByte.java
===================================================================
RCS file:
/cvsroot/firebird/client-java/src/main/org/firebirdsql/encodings/Encoding_OneByte.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -r1.4 -r1.5
23a24,26
> * Revision 1.5 2006/06/20 06:34:00 rrokytskyy
> * added encoding caching that can be enabled via jaybird.encoding.cache
> property
> *
65,66c68,69
< byte[] bufferB = new byte[128];
< char[] bufferC = new char[128];
---
> byte[] sharedBufferB = new byte[128];
> char[] sharedBufferC = new char[128];
70,75c73,86
< if (bufferB.length < str.length())
< bufferB = new byte[str.length()];
< int length = encodeToCharset(str.toCharArray(), 0, str.length(),
bufferB);
< byte[] result = new byte[length];
< System.arraycopy(bufferB, 0, result, 0, length);
< return result;
---
> if (EncodingFactory.USE_ENCODING_CACHING) {
> byte[] result = new byte[str.length()];
> encodeToCharset(str.toCharArray(), 0, str.length(), result);
> return result;
> } else {
> if (sharedBufferB.length < str.length())
> sharedBufferB = new byte[str.length()];
>
> int length = encodeToCharset(str.toCharArray(), 0,
> str.length(), sharedBufferB);
>
> byte[] result = new byte[length];
> System.arraycopy(sharedBufferB, 0, result, 0, length);
> return result;
> }
88,91c99,108
< if (bufferC.length < in.length)
< bufferC = new char[in.length];
< int length = decodeFromCharset(in, 0, in.length, bufferC);
< return new String(bufferC, 0, length);
---
> if (EncodingFactory.USE_ENCODING_CACHING) {
> char[] bufferC = new char[in.length];
> int length = decodeFromCharset(in, 0, in.length, bufferC);
> return new String(bufferC, 0, length);
> } else {
> if (sharedBufferC.length < in.length)
> sharedBufferC = new char[in.length];
> int length = decodeFromCharset(in, 0, in.length,
> sharedBufferC);
> return new String(sharedBufferC, 0, length);
> }

Roman