码迷,mamicode.com
首页 > 编程语言 > 详细

Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)

时间:2017-04-18 00:53:29      阅读:540      评论:0      收藏:0      [点我收藏+]

标签:string   logs   eve   效率   用户   random   申请   arch   文件的   

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

2、Java内存映射文件-MarchOn

3、Java Unsafe的使用-MarchOn

 

简单总结:

1、内存映射文件

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

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

Java申请空间时通常是从JVM堆内存分配的,即 ByteBuffer.allocate(int capacity) ,但其实还可以直接从物理内存(用户空间内存?)分配,即 ByteBuffer.allocateDirect(int capacity) ,后者其实调用了Unsafe类进行分配(见下节)。通常来说,后者的读写性能比前者的好,但是后者的分配比前者慢,特别是在数据量大的情况下差别更明显。

比较:

技术分享
 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值,所有记录以二进制形式存储在文件中

以上述三种方式读取每条记录(每种方式都是一次就分配足够的内存):

技术分享
 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 \n", 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());// 45ms
41         // ByteBuffer byteBuffer = ByteBuffer.allocate((int) randomAccessFileOutput.length());// 46ms
42         // while (inChannel.read(byteBuffer) > 0) {// 加上wihle后,分别用时77ms,120ms
43         byteBuffer.rewind();// 进入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

 

前两者要45ms左右,而内存映射文件只要22ms左右。

 

Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)

标签:string   logs   eve   效率   用户   random   申请   arch   文件的   

原文地址:http://www.cnblogs.com/z-sm/p/6725698.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!