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

Print this page




   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.security.AccessController;





  29 import sun.misc.Unsafe;
  30 import sun.misc.VM;
  31 
  32 /**
  33  * Access to bits, native and otherwise.
  34  */
  35 
  36 class Bits {                            // package-private
  37 
  38     private Bits() { }
  39 
  40 
  41     // -- Swapping --
  42 
  43     static short swap(short x) {
  44         return Short.reverseBytes(x);
  45     }
  46 
  47     static char swap(char x) {
  48         return Character.reverseBytes(x);


 604     private static boolean unalignedKnown = false;
 605 
 606     static boolean unaligned() {
 607         if (unalignedKnown)
 608             return unaligned;
 609         String arch = AccessController.doPrivileged(
 610             new sun.security.action.GetPropertyAction("os.arch"));
 611         unaligned = arch.equals("i386") || arch.equals("x86")
 612             || arch.equals("amd64") || arch.equals("x86_64");
 613         unalignedKnown = true;
 614         return unaligned;
 615     }
 616 
 617 
 618     // -- Direct memory management --
 619 
 620     // A user-settable upper limit on the maximum amount of allocatable
 621     // direct buffer memory.  This value may be changed during VM
 622     // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
 623     private static volatile long maxMemory = VM.maxDirectMemory();
 624     private static volatile long reservedMemory;
 625     private static volatile long totalCapacity;
 626     private static volatile long count;
 627     private static boolean memoryLimitSet = false;





 628 
 629     // These methods should be called whenever direct memory is allocated or
 630     // freed.  They allow the user to control the amount of direct memory
 631     // which a process may access.  All sizes are specified in bytes.
 632     static void reserveMemory(long size, int cap) {
 633         synchronized (Bits.class) {
 634             if (!memoryLimitSet && VM.isBooted()) {
 635                 maxMemory = VM.maxDirectMemory();
 636                 memoryLimitSet = true;
 637             }
 638             // -XX:MaxDirectMemorySize limits the total capacity rather than the
 639             // actual memory usage, which will differ when buffers are page
 640             // aligned.
 641             if (cap <= maxMemory - totalCapacity) {
 642                 reservedMemory += size;
 643                 totalCapacity += cap;
 644                 count++;






 645                 return;
 646             }
 647         }
 648 

 649         System.gc();




 650         try {
 651             Thread.sleep(100);
 652         } catch (InterruptedException x) {
 653             // Restore interrupt status
 654             Thread.currentThread().interrupt();












 655         }
 656         synchronized (Bits.class) {
 657             if (totalCapacity + cap > maxMemory)


 658                 throw new OutOfMemoryError("Direct buffer memory");
 659             reservedMemory += size;
 660             totalCapacity += cap;
 661             count++;




 662         }
 663 












 664     }
 665 
 666     static synchronized void unreserveMemory(long size, int cap) {
 667         if (reservedMemory > 0) {
 668             reservedMemory -= size;
 669             totalCapacity -= cap;
 670             count--;
 671             assert (reservedMemory > -1);
 672         }







 673     }
 674 
 675     // -- Monitoring of direct buffer usage --
 676 
 677     static {
 678         // setup access to this package in SharedSecrets
 679         sun.misc.SharedSecrets.setJavaNioAccess(
 680             new sun.misc.JavaNioAccess() {
 681                 @Override
 682                 public sun.misc.JavaNioAccess.BufferPool getDirectBufferPool() {
 683                     return new sun.misc.JavaNioAccess.BufferPool() {
 684                         @Override
 685                         public String getName() {
 686                             return "direct";
 687                         }
 688                         @Override
 689                         public long getCount() {
 690                             return Bits.count;
 691                         }
 692                         @Override
 693                         public long getTotalCapacity() {
 694                             return Bits.totalCapacity;
 695                         }
 696                         @Override
 697                         public long getMemoryUsed() {
 698                             return Bits.reservedMemory;
 699                         }
 700                     };
 701                 }
 702                 @Override
 703                 public ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) {
 704                     return new DirectByteBuffer(addr, cap, ob);
 705                 }
 706                 @Override
 707                 public void truncate(Buffer buf) {
 708                     buf.truncate();
 709                 }
 710         });
 711     }
 712 
 713     // -- Bulk get/put acceleration --
 714 
 715     // These numbers represent the point at which we have empirically
 716     // determined that the average cost of a JNI call exceeds the expense
 717     // of an element by element copy.  These numbers may change over time.
 718     static final int JNI_COPY_TO_ARRAY_THRESHOLD   = 6;




   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.security.AccessController;
  29 import java.util.concurrent.atomic.AtomicLong;
  30 import java.util.concurrent.atomic.LongAdder;
  31 
  32 import sun.misc.JavaLangRefAccess;
  33 import sun.misc.SharedSecrets;
  34 import sun.misc.Unsafe;
  35 import sun.misc.VM;
  36 
  37 /**
  38  * Access to bits, native and otherwise.
  39  */
  40 
  41 class Bits {                            // package-private
  42 
  43     private Bits() { }
  44 
  45 
  46     // -- Swapping --
  47 
  48     static short swap(short x) {
  49         return Short.reverseBytes(x);
  50     }
  51 
  52     static char swap(char x) {
  53         return Character.reverseBytes(x);


 609     private static boolean unalignedKnown = false;
 610 
 611     static boolean unaligned() {
 612         if (unalignedKnown)
 613             return unaligned;
 614         String arch = AccessController.doPrivileged(
 615             new sun.security.action.GetPropertyAction("os.arch"));
 616         unaligned = arch.equals("i386") || arch.equals("x86")
 617             || arch.equals("amd64") || arch.equals("x86_64");
 618         unalignedKnown = true;
 619         return unaligned;
 620     }
 621 
 622 
 623     // -- Direct memory management --
 624 
 625     // A user-settable upper limit on the maximum amount of allocatable
 626     // direct buffer memory.  This value may be changed during VM
 627     // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
 628     private static volatile long maxMemory = VM.maxDirectMemory();
 629     private static final AtomicLong reservedMemory = new AtomicLong();
 630     private static final AtomicLong totalCapacity = new AtomicLong();
 631     private static final AtomicLong count = new AtomicLong();
 632     private static volatile boolean memoryLimitSet = false;
 633     // max. number of sleeps during try-reserving with exponentially
 634     // increasing delay before throwing OutOfMemoryError:
 635     // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
 636     // which means that OOME will be thrown after 0.5 s of trying
 637     private static final int MAX_SLEEPS = 9;
 638 
 639     // These methods should be called whenever direct memory is allocated or
 640     // freed.  They allow the user to control the amount of direct memory
 641     // which a process may access.  All sizes are specified in bytes.
 642     static void reserveMemory(long size, int cap) {
 643 
 644         if (!memoryLimitSet && VM.isBooted()) {
 645             maxMemory = VM.maxDirectMemory();
 646             memoryLimitSet = true;
 647         }
 648 
 649         // optimist!
 650         if (tryReserveMemory(size, cap)) {
 651             return;
 652         }
 653 
 654         final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
 655 
 656         // retry while helping enqueue pending Reference objects
 657         // which includes executing pending Cleaner(s) which includes
 658         // Cleaner(s) that free direct buffer memory
 659         while (jlra.tryHandlePendingReference()) {
 660             if (tryReserveMemory(size, cap)) {
 661                 return;
 662             }
 663         }
 664 
 665         // trigger VM's Reference processing
 666         System.gc();
 667 
 668         // a retry loop with exponential back-off delays
 669         // (this gives VM some time to do it's job)
 670         boolean interrupted = false;
 671         try {
 672             long sleepTime = 1;
 673             int sleeps = 0;
 674             while (true) {
 675                 if (tryReserveMemory(size, cap)) {
 676                     return;
 677                 }
 678                 if (sleeps >= MAX_SLEEPS) {
 679                     break;
 680                 }
 681                 if (!jlra.tryHandlePendingReference()) {
 682                     try {
 683                         Thread.sleep(sleepTime);
 684                         sleepTime <<= 1;
 685                         sleeps++;
 686                     } catch (InterruptedException e) {
 687                         interrupted = true;
 688                     }
 689                 }
 690             }
 691 
 692             // no luck
 693             throw new OutOfMemoryError("Direct buffer memory");
 694 
 695         } finally {
 696             if (interrupted) {
 697                 // don't swallow interrupts
 698                 Thread.currentThread().interrupt();
 699             }
 700         }
 701     }
 702 
 703     private static boolean tryReserveMemory(long size, int cap) {
 704 
 705         // -XX:MaxDirectMemorySize limits the total capacity rather than the
 706         // actual memory usage, which will differ when buffers are page
 707         // aligned.
 708         long totalCap;
 709         while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
 710             if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
 711                 reservedMemory.addAndGet(size);
 712                 count.incrementAndGet();
 713                 return true;
 714             }
 715         }
 716 
 717         return false;





 718     }
 719 
 720 
 721     static void unreserveMemory(long size, int cap) {
 722         long cnt = count.decrementAndGet();
 723         long reservedMem = reservedMemory.addAndGet(-size);
 724         long totalCap = totalCapacity.addAndGet(-cap);
 725         assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
 726     }
 727 
 728     // -- Monitoring of direct buffer usage --
 729 
 730     static {
 731         // setup access to this package in SharedSecrets
 732         sun.misc.SharedSecrets.setJavaNioAccess(
 733             new sun.misc.JavaNioAccess() {
 734                 @Override
 735                 public sun.misc.JavaNioAccess.BufferPool getDirectBufferPool() {
 736                     return new sun.misc.JavaNioAccess.BufferPool() {
 737                         @Override
 738                         public String getName() {
 739                             return "direct";
 740                         }
 741                         @Override
 742                         public long getCount() {
 743                             return Bits.count.get();
 744                         }
 745                         @Override
 746                         public long getTotalCapacity() {
 747                             return Bits.totalCapacity.get();
 748                         }
 749                         @Override
 750                         public long getMemoryUsed() {
 751                             return Bits.reservedMemory.get();
 752                         }
 753                     };
 754                 }
 755                 @Override
 756                 public ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) {
 757                     return new DirectByteBuffer(addr, cap, ob);
 758                 }
 759                 @Override
 760                 public void truncate(Buffer buf) {
 761                     buf.truncate();
 762                 }
 763         });
 764     }
 765 
 766     // -- Bulk get/put acceleration --
 767 
 768     // These numbers represent the point at which we have empirically
 769     // determined that the average cost of a JNI call exceeds the expense
 770     // of an element by element copy.  These numbers may change over time.
 771     static final int JNI_COPY_TO_ARRAY_THRESHOLD   = 6;