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
  • 相关阅读:
    Docker优势
    jdk-tomcat-jenkens 安装
    SQL-2--TRIGGER
    边工作边刷题:70天一遍leetcode: day 92
    边工作边刷题:70天一遍leetcode: day 39
    边工作边刷题:70天一遍leetcode: day 96
    边工作边刷题:70天一遍leetcode: day 1
    边工作边刷题:70天一遍leetcode: day 94
    边工作边刷题:70天一遍leetcode: day 95
    边工作边刷题:70天一遍leetcode: day 97
  • 原文地址:https://www.cnblogs.com/z-sm/p/6725698.html
Copyright © 2011-2022 走看看