zoukankan      html  css  js  c++  java
  • Java直接内存与堆内存

    NIO的Buffer提供了一个可以不经过JVM内存直接访问系统物理内存的类——DirectBuffer。 DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同,普通的ByteBuffer仍在JVM堆上分配内存,其最大内存受到最大堆内存的限制;而DirectBuffer直接分配在物理内存中,并不占用堆空间,其可申请的最大内存受操作系统限制。

    直接内存的读写操作比普通Buffer快,但它的创建、销毁比普通Buffer慢(猜测原因是DirectBuffer需向OS申请内存涉及到用户态内核态切换,而后者则直接从堆内存划内存即可)。

    因此直接内存使用于需要大内存空间且频繁访问的场合,不适用于频繁申请释放内存的场合。

    (Note:DirectBuffer并没有真正向OS申请分配内存,其最终还是通过调用Unsafe的allocateMemory()来进行内存分配。不过JVM对Direct Memory可申请的大小也有限制,可用-XX:MaxDirectMemorySize=1M设置,这部分内存不受JVM垃圾回收管理。

    使用对外内存的原因:

    • 对垃圾回收停顿的改善。由于堆外内存是直接受操作系统管理而不是JVM,所以当我们使用堆外内存时,即可保持较小的堆内内存规模。从而在GC时减少回收停顿对于应用的影响。
    • 提升程序I/O操作的性能。通常在I/O通信过程中,会存在堆内内存到堆外内存的数据拷贝操作,对于需要频繁进行内存间数据拷贝且生命周期较短的暂存数据,都建议存储到堆外内存。

    以下是一些测试:

    代码:

     1 class DirectMemory {
     2 
     3     // 分配堆内存
     4     public static void bufferAccess() {
     5         long startTime = System.currentTimeMillis();
     6         ByteBuffer b = ByteBuffer.allocate(500);
     7         for (int i = 0; i < 1000000; i++) {
     8             for (int j = 0; j < 99; j++)
     9                 b.putInt(j);
    10             b.flip();
    11             for (int j = 0; j < 99; j++)
    12                 b.getInt();
    13             b.clear();
    14         }
    15         long endTime = System.currentTimeMillis();
    16         System.out.println("access_nondirect:" + (endTime - startTime));
    17     }
    18 
    19     // 直接分配内存
    20     public static void directAccess() {
    21         long startTime = System.currentTimeMillis();
    22         ByteBuffer b = ByteBuffer.allocateDirect(500);
    23         for (int i = 0; i < 1000000; i++) {
    24             for (int j = 0; j < 99; j++)
    25                 b.putInt(j);
    26             b.flip();
    27             for (int j = 0; j < 99; j++)
    28                 b.getInt();
    29             b.clear();
    30         }
    31         long endTime = System.currentTimeMillis();
    32         System.out.println("access_direct:" + (endTime - startTime));
    33     }
    34 
    35     public static void bufferAllocate() {
    36         long startTime = System.currentTimeMillis();
    37         for (int i = 0; i < 1000000; i++) {
    38             ByteBuffer.allocate(1000);
    39         }
    40         long endTime = System.currentTimeMillis();
    41         System.out.println("allocate_nondirect:" + (endTime - startTime));
    42     }
    43 
    44     public static void directAllocate() {
    45         long startTime = System.currentTimeMillis();
    46         for (int i = 0; i < 1000000; i++) {
    47             ByteBuffer.allocateDirect(1000);
    48         }
    49         long endTime = System.currentTimeMillis();
    50         System.out.println("allocate_direct:" + (endTime - startTime));
    51     }
    52 
    53     public static void main(String args[]) {
    54         System.out.println("访问性能测试:");
    55         bufferAccess();
    56         directAccess();
    57 
    58         System.out.println();
    59 
    60         System.out.println("分配性能测试:");
    61         bufferAllocate();
    62         directAllocate();
    63     }
    64 }
    View Code

    结果:

    访问性能测试:
    access_nondirect:157
    access_direct:134
    
    分配性能测试:
    allocate_nondirect:231
    allocate_direct:613

    可见与在JVM堆分配内存(allocate)相比,直接内存分配(allocateDirect)的访问性能更好,但分配较慢。(一般如此,当然数据量小的话差别不是那么明显)

  • 相关阅读:
    算法题
    AIO和NIO的理解
    Redis面试考点
    对MVVM的理解
    Vuex状态管理模式
    vue 的computed 和 watch 两者的区别
    vue之组件通信
    vue生命周期钩子函数
    angularjs 运行时报错ERROR in node_modules/rxjs/internal/types.d.ts(81,44): error TS1005: ';' expected. node_modules/rxjs/internal/types.d.ts(81,74): error TS1005: ';' expected. node_modules/rxjs/internal/t
    浅入不深出--vuex的简单使用
  • 原文地址:https://www.cnblogs.com/z-sm/p/6235157.html
Copyright © 2011-2022 走看看