< prev index next >

src/java.base/share/classes/java/nio/Bits.java

Print this page




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.nio;
  27 

  28 import java.util.concurrent.atomic.AtomicLong;

  29 
  30 import jdk.internal.misc.JavaNioAccess;
  31 import jdk.internal.misc.JavaLangRefAccess;
  32 import jdk.internal.misc.SharedSecrets;
  33 import jdk.internal.misc.Unsafe;
  34 import jdk.internal.misc.VM;

  35 
  36 /**
  37  * Access to bits, native and otherwise.
  38  */
  39 
  40 class Bits {                            // package-private
  41 
  42     private Bits() { }
  43 
  44 
  45     // -- Swapping --
  46 
  47     static short swap(short x) {
  48         return Short.reverseBytes(x);
  49     }
  50 
  51     static char swap(char x) {
  52         return Character.reverseBytes(x);
  53     }
  54 


 580             pageSize = unsafe().pageSize();
 581         return pageSize;
 582     }
 583 
 584     static int pageCount(long size) {
 585         return (int)(size + (long)pageSize() - 1L) / pageSize();
 586     }
 587 
 588     private static boolean unaligned = unsafe.unalignedAccess();
 589 
 590     static boolean unaligned() {
 591         return unaligned;
 592     }
 593 
 594 
 595     // -- Direct memory management --
 596 
 597     // A user-settable upper limit on the maximum amount of allocatable
 598     // direct buffer memory.  This value may be changed during VM
 599     // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
 600     private static volatile long maxMemory = VM.maxDirectMemory();




 601     private static final AtomicLong reservedMemory = new AtomicLong();
 602     private static final AtomicLong totalCapacity = new AtomicLong();
 603     private static final AtomicLong count = new AtomicLong();
 604     private static volatile boolean memoryLimitSet;
 605 
 606     // max. number of sleeps during try-reserving with exponentially
 607     // increasing delay before throwing OutOfMemoryError:
 608     // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
 609     // which means that OOME will be thrown after 0.5 s of trying
 610     private static final int MAX_SLEEPS = 9;





































 611 
 612     // These methods should be called whenever direct memory is allocated or
 613     // freed.  They allow the user to control the amount of direct memory
 614     // which a process may access.  All sizes are specified in bytes.
 615     static void reserveMemory(long size, int cap) {
 616 
 617         if (!memoryLimitSet && VM.initLevel() >= 1) {
 618             maxMemory = VM.maxDirectMemory();
 619             memoryLimitSet = true;
 620         }
 621 


 622         // optimist!






 623         if (tryReserveMemory(size, cap)) {
 624             return;
 625         }




 626 
 627         final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
 628 
 629         // retry while helping enqueue pending Reference objects
 630         // which includes executing pending Cleaner(s) which includes
 631         // Cleaner(s) that free direct buffer memory
 632         while (jlra.tryHandlePendingReference()) {




 633             if (tryReserveMemory(size, cap)) {
 634                 return;
 635             }
 636         }

 637 
 638         // trigger VM's Reference processing
 639         System.gc();
 640 
 641         // a retry loop with exponential back-off delays
 642         // (this gives VM some time to do it's job)
 643         boolean interrupted = false;
 644         try {
 645             long sleepTime = 1;
 646             int sleeps = 0;
 647             while (true) {
 648                 if (tryReserveMemory(size, cap)) {
 649                     return;
 650                 }
 651                 if (sleeps >= MAX_SLEEPS) {
 652                     break;
 653                 }
 654                 if (!jlra.tryHandlePendingReference()) {
 655                     try {
 656                         Thread.sleep(sleepTime);
 657                         sleepTime <<= 1;
 658                         sleeps++;
 659                     } catch (InterruptedException e) {
 660                         interrupted = true;
 661                     }
 662                 }
 663             }
 664 
 665             // no luck
 666             throw new OutOfMemoryError("Direct buffer memory");
 667 
 668         } finally {
 669             if (interrupted) {
 670                 // don't swallow interrupts
 671                 Thread.currentThread().interrupt();
 672             }
 673         }
 674     }
 675 
 676     private static boolean tryReserveMemory(long size, int cap) {
 677 
 678         // -XX:MaxDirectMemorySize limits the total capacity rather than the
 679         // actual memory usage, which will differ when buffers are page
 680         // aligned.
 681         long totalCap;
 682         while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
 683             if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
 684                 reservedMemory.addAndGet(size);
 685                 count.incrementAndGet();
 686                 return true;
 687             }
 688         }
 689 
 690         return false;
 691     }
 692 





















































 693 
 694     static void unreserveMemory(long size, int cap) {

 695         long cnt = count.decrementAndGet();
 696         long reservedMem = reservedMemory.addAndGet(-size);
 697         long totalCap = totalCapacity.addAndGet(-cap);
 698         assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;



 699     }
 700 
 701     // -- Monitoring of direct buffer usage --
 702 
 703     static {
 704         // setup access to this package in SharedSecrets
 705         SharedSecrets.setJavaNioAccess(
 706             new JavaNioAccess() {
 707                 @Override
 708                 public JavaNioAccess.BufferPool getDirectBufferPool() {
 709                     return new JavaNioAccess.BufferPool() {
 710                         @Override
 711                         public String getName() {
 712                             return "direct";
 713                         }
 714                         @Override
 715                         public long getCount() {
 716                             return Bits.count.get();
 717                         }
 718                         @Override




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.nio;
  27 
  28 import java.util.concurrent.TimeUnit;
  29 import java.util.concurrent.atomic.AtomicLong;
  30 import java.util.concurrent.locks.StampedLock;
  31 
  32 import jdk.internal.misc.JavaNioAccess;
  33 import jdk.internal.misc.JavaLangRefAccess;
  34 import jdk.internal.misc.SharedSecrets;
  35 import jdk.internal.misc.Unsafe;
  36 import jdk.internal.misc.VM;
  37 import jdk.internal.ref.CleanerFactory;
  38 
  39 /**
  40  * Access to bits, native and otherwise.
  41  */
  42 
  43 class Bits {                            // package-private
  44 
  45     private Bits() { }
  46 
  47 
  48     // -- Swapping --
  49 
  50     static short swap(short x) {
  51         return Short.reverseBytes(x);
  52     }
  53 
  54     static char swap(char x) {
  55         return Character.reverseBytes(x);
  56     }
  57 


 583             pageSize = unsafe().pageSize();
 584         return pageSize;
 585     }
 586 
 587     static int pageCount(long size) {
 588         return (int)(size + (long)pageSize() - 1L) / pageSize();
 589     }
 590 
 591     private static boolean unaligned = unsafe.unalignedAccess();
 592 
 593     static boolean unaligned() {
 594         return unaligned;
 595     }
 596 
 597 
 598     // -- Direct memory management --
 599 
 600     // A user-settable upper limit on the maximum amount of allocatable
 601     // direct buffer memory.  This value may be changed during VM
 602     // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
 603     // A change to maxMemory is published via memoryLimitSet volatile boolean
 604     // flag changing state from false -> true, so maxMemory need not be volatile.
 605     private static long maxMemory = VM.maxDirectMemory();
 606     private static volatile boolean memoryLimitSet;
 607 
 608     private static final AtomicLong reservedMemory = new AtomicLong();
 609     private static final AtomicLong totalCapacity = new AtomicLong();
 610     private static final AtomicLong count = new AtomicLong();

 611 
 612     // A fair lock for direct memory allocator threads to queue after 1st optimistic
 613     // reservation fails so that only a single thread at a time is retrying
 614     // reservation while:
 615     //   - waiting for unreservation events until time out
 616     //   - followed by triggering reference discovery
 617     //   - followed by another round of waiting for unreservation events until time out
 618     // ... before finally giving up with OutOfMemoryError.
 619     private static final StampedLock reserveLock = new StampedLock();
 620 
 621     // A counter of unreservations incremented by unreservation threads,
 622     // guarded by unreserveLock, but also read by reservation threads without
 623     // holding unreserveLock, so it must be volatile.
 624     private static volatile int unreserveCount;
 625 
 626     // Last value of 'unreserveCount' observed by reservation threads,
 627     // guarded by reserveLock. If 'lastUnreserveCount' and 'unreserveCount'
 628     // differ, an unreservation event (or multiple events) is detected.
 629     private static int lastUnreserveCount;
 630 
 631     // the System.nanoTime() of the detection of last unreservation event
 632     // by the reservation thread(s), guarded by reserveLock.
 633     private static long lastUnreserveNanoTime;
 634 
 635     // flag indicating if 'lastUnreserveNanoTime' has already been set,
 636     // guarded by reserveLock.
 637     private static boolean lastUnreserveNanoTimeSet;
 638 
 639     // max. wait time for unreservation event before triggering GC and/or
 640     // failing with OOME.
 641     private static final long MAX_UNRESERVE_WAIT_NANOS =
 642         TimeUnit.SECONDS.toNanos(1L);
 643 
 644     // the duration of last successful waiting for unreservation
 645     // event by reservation thread. starts with MAX_UNRESERVE_WAIT_NANOS / 4
 646     // and is dynamically adjusted at each successful call to awaitUnreserveMemory()
 647     // that actually waited for the event.
 648     private static long lastSuccessfullUnreserveWaitNanos =
 649         MAX_UNRESERVE_WAIT_NANOS / 4;
 650 
 651     // monitor lock via which unreservation threads notify reservation threads
 652     // about the unreservation events.
 653     private static final Object unreserveLock = new Object();
 654 
 655     // These methods should be called whenever direct memory is allocated or
 656     // freed.  They allow the user to control the amount of direct memory
 657     // which a process may access.  All sizes are specified in bytes.
 658     static void reserveMemory(long size, int cap) {
 659 
 660         if (!memoryLimitSet && VM.initLevel() >= 1) {
 661             maxMemory = VM.maxDirectMemory();
 662             memoryLimitSet = true;
 663         }
 664 
 665         JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
 666 
 667         // optimist!
 668         long stamp = reserveLock.tryReadLock();
 669         if (stamp != 0L) try {
 670             // retry reservation while helping the Cleaner thread process enqueued
 671             // Cleanable(s) which includes the ones that free direct buffer memory
 672             // until the queue drains out
 673             do {
 674                 if (tryReserveMemory(size, cap)) {
 675                     return;
 676                 }
 677             } while (jlra.cleanNextEnqueuedCleanable(CleanerFactory.cleaner()));
 678         } finally {
 679             reserveLock.unlockRead(stamp);
 680         }
 681 
 682         // reservation threads that don't succeed at first must queue so that
 683         // only one of them at a time is triggering reference discovery and
 684         // retrials with waiting on un-reservation events...
 685         stamp = reserveLock.writeLock();
 686         try {
 687             // retry reservation until there are no unreservation events
 688             // detected for at least 4 times as much as we waited for last
 689             // successful unreservation event but no more than
 690             // MAX_UNRESERVE_WAIT_NANOS.
 691             do {
 692                 if (tryReserveMemory(size, cap)) {
 693                     return;
 694                 }
 695             } while (awaitUnreserveMemory(Math.min(MAX_UNRESERVE_WAIT_NANOS,
 696                                                    lastSuccessfullUnreserveWaitNanos * 4)));
 697 
 698             // trigger reference discovery
 699             System.gc();
 700             // GC stops the world and can last for a long time,
 701             // so restart timing from 0.
 702             lastUnreserveNanoTime = System.nanoTime();
 703 
 704             // retry reservation until there are no unreservation events
 705             // detected for at least MAX_UNRESERVE_WAIT_NANOS.
 706             do {

 707                 if (tryReserveMemory(size, cap)) {
 708                     return;
 709                 }
 710             } while (awaitUnreserveMemory(MAX_UNRESERVE_WAIT_NANOS));












 711 
 712             // no luck
 713             throw new OutOfMemoryError("Direct buffer memory");

 714         } finally {
 715             reserveLock.unlockWrite(stamp);



 716         }
 717     }
 718 
 719     private static boolean tryReserveMemory(long size, int cap) {
 720 
 721         // -XX:MaxDirectMemorySize limits the total capacity rather than the
 722         // actual memory usage, which will differ when buffers are page
 723         // aligned.
 724         long totalCap;
 725         while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
 726             if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
 727                 reservedMemory.addAndGet(size);
 728                 count.incrementAndGet();
 729                 return true;
 730             }
 731         }
 732 
 733         return false;
 734     }
 735 
 736     private static boolean awaitUnreserveMemory(long timeoutNanos) {
 737         assert reserveLock.isWriteLocked();
 738 
 739         // optimistic 1st try without lock
 740         int c;
 741         if ((c = unreserveCount) != lastUnreserveCount) {
 742             lastUnreserveCount = c;
 743             lastUnreserveNanoTime = System.nanoTime();
 744             lastUnreserveNanoTimeSet = true;
 745             return true;
 746         }
 747         boolean interrupted = false;
 748         try {
 749             synchronized (unreserveLock) {
 750                 long nt = System.nanoTime();
 751                 if (!lastUnreserveNanoTimeSet) {
 752                     lastUnreserveNanoTime = nt;
 753                     lastUnreserveNanoTimeSet = true;
 754                 }
 755                 long deadline = lastUnreserveNanoTime + timeoutNanos;
 756                 long waitUnreserve;
 757                 while ((c = unreserveCount) == lastUnreserveCount &&
 758                        (waitUnreserve = deadline - nt) > 0L) {
 759                     interrupted |= waitNanos(unreserveLock, waitUnreserve);
 760                     nt = System.nanoTime();
 761                 }
 762                 if (c == lastUnreserveCount) {
 763                     // time out
 764                     return false;
 765                 } else {
 766                     lastSuccessfullUnreserveWaitNanos = nt - lastUnreserveNanoTime;
 767                     lastUnreserveCount = c;
 768                     lastUnreserveNanoTime = nt;
 769                     return true;
 770                 }
 771             }
 772         } finally {
 773             if (interrupted) {
 774                 Thread.currentThread().interrupt();
 775             }
 776         }
 777     }
 778 
 779     private static boolean waitNanos(Object lock, long waitNanos) {
 780         try {
 781             long millis = TimeUnit.NANOSECONDS.toMillis(waitNanos);
 782             int nanos = (int) (waitNanos - TimeUnit.MILLISECONDS.toNanos(millis));
 783             lock.wait(millis, nanos);
 784             return false;
 785         } catch (InterruptedException e) {
 786             return true;
 787         }
 788     }
 789 
 790     static void unreserveMemory(long size, int cap) {
 791         synchronized (unreserveLock) {
 792             long cnt = count.decrementAndGet();
 793             long reservedMem = reservedMemory.addAndGet(-size);
 794             long totalCap = totalCapacity.addAndGet(-cap);
 795             assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
 796             unreserveCount++;
 797             unreserveLock.notifyAll();
 798         }
 799     }
 800 
 801     // -- Monitoring of direct buffer usage --
 802 
 803     static {
 804         // setup access to this package in SharedSecrets
 805         SharedSecrets.setJavaNioAccess(
 806             new JavaNioAccess() {
 807                 @Override
 808                 public JavaNioAccess.BufferPool getDirectBufferPool() {
 809                     return new JavaNioAccess.BufferPool() {
 810                         @Override
 811                         public String getName() {
 812                             return "direct";
 813                         }
 814                         @Override
 815                         public long getCount() {
 816                             return Bits.count.get();
 817                         }
 818                         @Override


< prev index next >