Skip to content
This repository has been archived by the owner on Mar 20, 2021. It is now read-only.

problem with PooledMemoryManager #1938

Closed
kentsang77 opened this issue May 23, 2017 · 6 comments
Closed

problem with PooledMemoryManager #1938

kentsang77 opened this issue May 23, 2017 · 6 comments

Comments

@kentsang77
Copy link

kentsang77 commented May 23, 2017

I have used HeapMemoryManager for a long time and everything works fine.
Last week we tried grizzly version 2.3.30 and found that message decoder doesn't work at all.
Last working grizzly version was 2.3.24.
After investigation, we found the default MemoryManager changed to PooledMemoryManager at 2.3.26 and there is a strange issue when allocating a large encoding buffer (say 4M):

final MemoryManager memoryManager = obtainMemoryManager(storage);
final Buffer output = memoryManager.allocate(1024 * 1024 * 4); // ok if 4k but not 4m

The symptom is : only null bytes can be read at decoder.
I created a all in 1 class junit for your investigation.

StringMessageFilterTest.zip

@rlubke
Copy link
Member

rlubke commented May 23, 2017

@kentsang77 You're aware how to change the default memory manager back to HeapMemoryManager?

@kofemann
Copy link
Contributor

Try start jvm with

-Dorg.glassfish.grizzly.DEFAULT_MEMORY_MANAGER=org.glassfish.grizzly.memory.HeapMemoryManager

option

@rlubke rlubke self-assigned this May 25, 2017
@rlubke
Copy link
Member

rlubke commented May 26, 2017

The root of the issue is that with allocations that span multiple buffers, as is the case with the large allocation, the ByteBuffer you obtain from the Buffer isn't shared between the two.

The documentation for Buffer.toByteBuffer() states:

  • Converts this Buffer to a {@link ByteBuffer}.
    • If this Buffer is not composite - then returned
    • {@link ByteBuffer}'s content is a shared subsequence of this buffer's
    • content, with {@link CompositeBuffer} this is not guaranteed.
    • The position of the returned {@link ByteBuffer} is not guaranteed to be 0,
    • the capacity of the returned {@link ByteBuffer} is not guaranteed to be
    • equal to the capacity of this Buffer.
    • It is guaranteed that the result of the returned ByteBuffer's
    • {@link ByteBuffer#remaining()} call will be equal (limit - position).
    • The Buffer's and ByteBuffer's position, limit, and mark values are not
    • guaranteed to be independent, so it's recommended to save and restore
    • position, limit values if it is planned to change them or
    • {@link ByteBuffer#slice()} the returned {@link ByteBuffer}.

I have a question about the test case.

You do the following:

` final Buffer output = memoryManager.allocate(allocationSize);
final ByteBuffer byteBuffer = output.toByteBuffer().slice();

        final byte[] byteRepresentation;
        try {
            if (stringTerminator != null) {
                input = input + stringTerminator;
            }

            byteRepresentation = input.getBytes(charset.name());

            if (stringTerminator == null) {
                byteBuffer.putInt(byteRepresentation.length);
            }
            byteBuffer.put(byteRepresentation);
            output.limit(byteBuffer.position());

            LOGGER.log(Level.INFO, "encode byteBuffer = {0}", Arrays.toString(Arrays.copyOfRange(byteBuffer.array(), 0, 100)));

        } catch (Exception e) {
            return TransformationResult.createErrorResult(0,
                    "Exception during construction of byteBuffer, Exception = " + e.getMessage());
        }

`

Is there a reason you're converting to a ByteBuffer prior to manipulating? Was this only to demonstrate the problem or do you do this in production?

@kentsang77
Copy link
Author

It is currently doing at production.
All of my service messages are using jdk's ByteBuffer for serialization and deserialization.
I cannot change that to grizzly Buffer.

@rlubke
Copy link
Member

rlubke commented May 26, 2017

Then the option you have is a) Set the default memory manager to HeapMemoryManager or b) if the Buffer is composite, copy the ByteBuffer content back to the Buffer.

The latter option isn't ideal for performance reasons.

@kentsang77
Copy link
Author

kentsang77 commented May 27, 2017

My solution is to use a PooledMemoryManagerFactory to init a PooledMemoryManager with large enough DEFAULT_BASE_BUFFER_SIZE (where allocationSize < DEFAULT_BASE_BUFFER_SIZE ).

Personally I think if the PooledMemoryManager cannot handle large buffer size, it should throw exception. At least not just returning a weired empty buffer.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants