Allow to free direct buffers on java9 again#6568
Conversation
| DIRECT_BUFFER_CONSTRUCTOR != null ? "available" : "unavailable"); | ||
|
|
||
| if (direct != null) { | ||
| freeDirectBuffer(direct); |
There was a problem hiding this comment.
removing this makes it easier to break cycle references and its not super important anyway
|
@normanmaurer how about the non unsafe version? https://bugs.openjdk.java.net/browse/JDK-8148117 |
|
@johnou not sure i get your question... Can you explain ? |
| * For more details see <a href="https://github.com/netty/netty/issues/2604">#2604</a>. | ||
| */ | ||
| final class Cleaner0 { | ||
| final class Cleaner0 implements Cleaner { |
There was a problem hiding this comment.
I think its fine... @Scottmitch @nmittler @trustin PTAL
There was a problem hiding this comment.
It's a possible deadlock such as google/guava#1977?
There was a problem hiding this comment.
I think I found the cycle... stay tuned
|
@normanmaurer nvm, I misread "If, at some point in the future, it is determined that sun.misc.Cleaner is in fact a critical internal API ( with static usage ), |
|
@trustin PTAL as well |
cb58839 to
4fde8fa
Compare
| try { | ||
| Class<?> bitsClass = | ||
| Class.forName("java.nio.Bits", false, PlatformDependent.getSystemClassLoader()); | ||
| Class.forName("java.nio.Bits", false, getSystemClassLoader()); |
There was a problem hiding this comment.
This fixed a cycle reference
|
|
||
| if (direct != null) { | ||
| freeDirectBuffer(direct); | ||
| private static boolean explicitNoUnsafe0() { |
There was a problem hiding this comment.
I moved this from PlatformDependent to remove a cycle reference.
| INVOKE_CLEANER = method; | ||
| } | ||
|
|
||
| private static void freeDirectBuffer0(ByteBuffer buffer) { |
There was a problem hiding this comment.
is this method necessary? seems like it is only used in a single place
| } | ||
|
|
||
| static void freeDirectBuffer(ByteBuffer buffer) { | ||
| private static void freeDirectBuffer0(ByteBuffer buffer) { |
There was a problem hiding this comment.
I think we can remove this method, and just move the code into freeDirectBuffer. We invoke the cleaner above clean.invoke(cleaner); so we may be double freeing this buffer
| } | ||
|
|
||
| if (!hasUnsafe() && !isAndroid() && !IS_EXPLICIT_NO_UNSAFE) { | ||
| if (!hasUnsafe() && !isAndroid() && !PlatformDependent0.isExplicitNoUnsafe()) { |
There was a problem hiding this comment.
isExplicitNoUnsafe should be reflected in hasUnsafe ... can we just remove the !PlatformDependent0.isExplicitNoUnsafe() part?
| if (hasUnsafe() && !isAndroid()) { | ||
| // only direct to method if we are not running on android. | ||
| // See https://github.com/netty/netty/issues/2604 | ||
| CLEANER = javaVersion() >= 9 ? new CleanerJava9() : new Cleaner0(); |
There was a problem hiding this comment.
consider renaming Cleaner0 to CleanerJava6.
|
@Scottmitch addressed all of it... Good to merge ? |
There was a problem hiding this comment.
the conditional below checks if error == null and then says "cleaner is available". However this may not be the case if we have no unsafe. We should adjust the logic below or set the error = <exception indicating unsafe isn't available>.
There was a problem hiding this comment.
nit: remove this assert ... we will very likely NPE via a JVM trap below anyways.
There was a problem hiding this comment.
can we log a debug statement, or is this expected to happen frequently?
There was a problem hiding this comment.
i would argue this should never happen as we tried it before in the static block. Maybe best to throw an Error . WDYT ?
There was a problem hiding this comment.
yah if we never expect it to happen lets re-throw it. What about PlatformDependent.throwException(t);?
There was a problem hiding this comment.
we should also log something similar to the Java6 class if the cleaner is not supported.
There was a problem hiding this comment.
suggestion: instead of checking this condition every time we could have PlatformDependent detect if the cleaner is properly initialized, and if not just use the NOOP cleaner. We should do the same thing for the java6 class:
class CleanerJava9 {
static {
..
}
static boolean isInitialized() {
return INVOKE_CLEANER != null;
}
..
}
class PlatformDependent {
..
if (java9) {
CLEANER = CleanerJava9.isInitialized() ? new CleanerJava9() : NOOP;
} else {
CLEANER = CleanerJava6.isInitialized() ? new CleanerJava6() : NOOP;
}
...
}580c10b to
8de8345
Compare
|
|
||
| // free buffer if possible | ||
| freeDirectBuffer(direct); | ||
| public static boolean isSupported() { |
| INVOKE_CLEANER = method; | ||
| } | ||
|
|
||
| public static boolean isSupported() { |
| private static final Method INVOKE_CLEANER; | ||
|
|
||
| static { | ||
| Method method; |
|
|
||
| static { | ||
| Method method; | ||
| Throwable error; |
Motivation: Java9 adds a new method to Unsafe which allows to free direct ByteBuffer via the cleaner without the need to use an commandline arguments. Modifications: - Add Cleaner interface - Add CleanerJava9 which will be used when using Java9+ and take care of release direct ByteBuffer - Let Cleaner0 implement Cleaner Result: Be able to free direct ByteBuffer on Java9+ again without any commandline arguments.
| logger.debug("-Dio.netty.noPreferDirect: {}", !DIRECT_BUFFER_PREFERRED); | ||
| } | ||
|
|
||
| if (!hasUnsafe() && !isAndroid() && !IS_EXPLICIT_NO_UNSAFE) { |
There was a problem hiding this comment.
Why was this removed? It means that logging for this shows up even if no unsafe was explicitly set which was the point of adding this in the first place. It means that with Netty 4.1.10.Final our users are back to seeing a message that they don't understand that makes them think their system is broken. Unless there is a good reason that this is a removed (I'm sorry if I'm missing it), I would like to open a PR to add it back.
There was a problem hiding this comment.
Also, it seems to me that this change was not needed for the stated purpose of this change (to allow freeing direct buffers on JDK 9)? Again, maybe I'm missing something and if so I'm sorry.
Adding unrelated changes to PRs makes it hard to follow what is going on. I follow this repository, if I see a change titled "Allow to free direct buffers on java9 again" I think I know what it's about and I skip reading the code change. If an unrelated code change is slipped in, how can I as a follower know this without reading every code change which I think is an unreasonable assumption?
Had this been in a separate PR I would have seen it and would have responded then to please not remove it.
|
There was no good reason and it's my fault to miss this :(
Can you please do a PR and also add a comment in the code why it should never be removed again.
Sorry again for the trouble
… Am 03.05.2017 um 05:36 schrieb Jason Tedor ***@***.***>:
@jasontedor commented on this pull request.
In common/src/main/java/io/netty/util/internal/PlatformDependent.java:
> @@ -122,7 +127,7 @@ public Random current() {
logger.debug("-Dio.netty.noPreferDirect: {}", !DIRECT_BUFFER_PREFERRED);
}
- if (!hasUnsafe() && !isAndroid() && !IS_EXPLICIT_NO_UNSAFE) {
Relates #5624
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub, or mute the thread.
|
|
Thank you for understanding @normanmaurer! I will open a PR soon.
I will do this! 😄 |
|
I opened #6696. |
Motivation:
Java9 adds a new method to Unsafe which allows to free direct ByteBuffer via the cleaner without the need to use an commandline arguments.
Modifications:
Result:
Be able to free direct ByteBuffer on Java9+ again without any commandline arguments.