zoukankan      html  css  js  c++  java
  • 目录_Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)

    1、Java直接内存与堆内存-MarchOn

    2、Java内存映射文件-MarchOn

    3、Java Unsafe的使用-MarchOn

    简单总结:

    1、内存映射文件

    读文件时候一般要两次复制:从磁盘复制到内核空间再复制到用户空间,内存映射文件避免了第二次复制,且内存分配在内核空间,应用程序访问的就是操作系统的内核内存空间,因此极大提高了读取效率。写文件同理。

    2、堆内存分配与直接内存分配:

    Java申请空间时通常是从JVM堆内存分配的,即 ByteBuffer.allocate(int capacity) ,但其实还可以直接从物理内存(用户空间内存?)分配,即 ByteBuffer.allocateDirect(int capacity) ,后者其实调用了Unsafe类进行分配(见下节)。后者的分配原理是这样的:使用Native函数库直接分配堆外内存,通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,从而避免了在java堆和Native堆之间复制数据的开销。

    通常来说,由于后者避免了数据在堆外内存和JVM堆内存间的复制,所以读写性能比前者的好,但是后者的分配比前者慢,特别是在数据量大的情况下差别更明显。此外,直接内存常被用来扩展可用的内存区域。

    比较:

     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 }
    65 
    66 //结果
    67 
    68 访问性能测试:
    69 access_nondirect:160
    70 access_direct:135
    71 
    72 分配性能测试:
    73 allocate_nondirect:231
    74 allocate_direct:644
    View Code

    3、Unsafe类

    直接内存分配(allocateDirect)其实就是调用了sun.misc.Unsafe类来进行内存分配,Unsafe是sun.*API中的类,它不是J2SE中真正的一部份。

    关于JVM对内存分配、直接内存分配、内存映射文件的一个测试示例:

    2684862条记录,每条记录包含4个long值,所有记录以二进制形式存储在文件中

    以上述三种方式读取每条记录(每种方式都是一次就分配足够的内存,直接内存分配、JVM内存分配、内存映射文件三者分别用时35ms、46ms、22ms):

     1 package buaa.act.ucar.imtg.main;
     2 
     3 import java.io.IOException;
     4 import java.io.RandomAccessFile;
     5 import java.nio.ByteBuffer;
     6 import java.nio.channels.FileChannel;
     7 import java.nio.channels.FileChannel.MapMode;
     8 
     9 /**
    10  * @author zsm
    11  * @date 2017年3月3日 上午10:23:53
    12  */
    13 public class Test {
    14     public static void main(String[] args)
    15             throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
    16         long startTime, dataCount;
    17 
    18         try {
    19             startTime = System.currentTimeMillis();
    20             System.out.println("reading");
    21             dataCount = readFromMMFile("F:/gps data/2016-11-11 18087 60399647/beijing_0900-1500_2684862.binary");
    22             System.out.printf("reading %d data,time used:%d ms 
    ", dataCount,
    23                     (System.currentTimeMillis() - startTime));
    24         } catch (IOException e) {
    25             // TODO Auto-generated catch block
    26             e.printStackTrace();
    27         }
    28 
    29     }
    30 
    31     public static long readFromFile(String srcFilePath) throws IOException {
    32 
    33         RandomAccessFile randomAccessFileOutput = new RandomAccessFile(srcFilePath, "rw");
    34         FileChannel inChannel = randomAccessFileOutput.getChannel();
    35 
    36         long devsn, gpstime;
    37         double longitude, latitude;
    38         long dataCount = 0;
    39 
    40         ByteBuffer byteBuffer = ByteBuffer.allocateDirect((int) randomAccessFileOutput.length());// 35ms
    41         // ByteBuffer byteBuffer = ByteBuffer.allocate((int) randomAccessFileOutput.length());// 46ms
    42          while (inChannel.read(byteBuffer) > 0) {
    43         byteBuffer.flip();// 进入read模式
    44         while (byteBuffer.hasRemaining()) {
    45             devsn = byteBuffer.getLong();
    46             gpstime = byteBuffer.getLong();
    47             longitude = Double.longBitsToDouble(byteBuffer.getLong());
    48             latitude = Double.longBitsToDouble(byteBuffer.getLong());
    49             // System.out.println(devsn + " " + gpstime + " " + longitude + " " + latitude);
    50             dataCount++;
    51         }
    52         byteBuffer.clear();// 进入write模式
    53         }
    54         inChannel.close();
    55         randomAccessFileOutput.close();
    56         return dataCount;
    57     }
    58 
    59     // 22ms
    60     public static long readFromMMFile(String srcFilePath) throws IOException {
    61         RandomAccessFile randomAccessFileOutput = new RandomAccessFile(srcFilePath, "rw");
    62         FileChannel inChannel = randomAccessFileOutput.getChannel();
    63 
    64         long devsn, gpstime;
    65         double longitude, latitude;
    66         long dataCount = 0;
    67         ByteBuffer byteBuffer = inChannel.map(MapMode.READ_ONLY, 0, randomAccessFileOutput.length());
    68         while (byteBuffer.hasRemaining()) {
    69             devsn = byteBuffer.getLong();
    70             gpstime = byteBuffer.getLong();
    71             longitude = Double.longBitsToDouble(byteBuffer.getLong());
    72             latitude = Double.longBitsToDouble(byteBuffer.getLong());
    73             // System.out.println(devsn + " " + gpstime + " " + longitude + " " + latitude);
    74             dataCount++;
    75         }
    76         inChannel.close();
    77         randomAccessFileOutput.close();
    78         return dataCount;
    79     }
    80 
    81 }
    View Code
  • 相关阅读:
    URAL——DFS找规律——Nudnik Photographer
    URAL1353——DP——Milliard Vasya's Function
    URAL1203——DPor贪心——Scientific Conference
    递推DP HDOJ 5389 Zero Escape
    区间DP UVA 1351 String Compression
    树形DP UVA 1292 Strategic game
    Manacher HDOJ 5371 Hotaru's problem
    同余模定理 HDOJ 5373 The shortest problem
    递推DP HDOJ 5375 Gray code
    最大子序列和 HDOJ 1003 Max Sum
  • 原文地址:https://www.cnblogs.com/z-sm/p/6725698.html
Copyright © 2011-2022 走看看