JDK-8316156 : ByteArrayInputStream.transferTo causes MaxDirectMemorySize overflow
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 11,17,21,22
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2023-09-13
  • Updated: 2025-04-18
  • Resolved: 2023-09-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 17 JDK 21 JDK 22
17.0.16Fixed 21.0.2Fixed 22 b16Fixed
Related Reports
Causes :  
Description
Consider the following:
```
        try (FileChannel fc = FileChannel.open(file, CREATE, WRITE)) {
            OutputStream out = Channels.newOutputStream(fc);
            byte[] b = new byte[10*1024*1024];
            out.write(b);
        }
```
This will invoke FileChannel.write with a BB that is backed by the byte array, this needs to be copied into a direct buffer to do the actual I/O. In this case, it will allocate a temporary direct buffer of 10Mb.

There is an argument that the channel implementations should limit their direct memory usage but these are low-level classes. It may be better to limit the writes to the channels instead, e.g. ChannelOutputStream.writeFully could be work like this:

```
    private void writeFully(ByteBuffer bb) throws IOException {
        int pos = bb.position();
        int rem = bb.limit() - pos;
        while (rem > 0) {
            bb.limit(pos + Integer.min(rem, DEFAULT_BUFFER_SIZE));
            int n = ch.write(bb);
            if (n <= 0)
                throw new RuntimeException("no bytes written");
            pos += n;
            rem -=n;
        }
    }
```


Comments
[jdk17u-fix-request] Approval Request from Daniel Hu Fixes bug with ByteArrayInputStream.transferTo causing an memory overflow in certain scenarios. Applies cleanly. Already backported to 21 and released since 21.0.2. New test fails without the fix, and passes with it. Risk is low given the small change and length of time in 21.
17-04-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk17u-dev/pull/3507 Date: 2025-04-16 19:17:27 +0000
17-04-2025

A pull request was submitted for review. URL: https://git.openjdk.org/jdk21u/pull/227 Date: 2023-10-04 16:53:56 +0000
04-10-2023

Changeset: 5cacf212 Author: Brian Burkhalter <bpb@openjdk.org> Date: 2023-09-20 20:42:31 +0000 URL: https://git.openjdk.org/jdk/commit/5cacf212f066f5694d01f0891adfbe8b38660175
20-09-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/15733 Date: 2023-09-14 03:05:50 +0000
20-09-2023

A similar situation obtains when reading using ChannelInputStream. For example, if one invokes Files.readAllBytes on a large enough file, an OOME will be thrown.
13-09-2023

Failing due to limited direct memory may be reproduced as: echo 'java.nio.file.Files.copy(new java.io.ByteArrayInputStream(new byte[256*1024*1024]), java.nio.file.Path.of("/tmp/aaa"), java.nio.file.StandardCopyOption.REPLACE_EXISTING);' | jshell -R-XX:MaxDirectMemorySize=25M
13-09-2023