java分配直接内存吗_目录_Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)...

简单总结:

1、内存映射文件

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

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

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

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

比较:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 classDirectMemory {2

3 //分配堆内存

4 public static voidbufferAccess() {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 voiddirectAccess() {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 voidbufferAllocate() {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 voiddirectAllocate() {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 voidmain(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):

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagebuaa.act.ucar.imtg.main;2

3 importjava.io.IOException;4 importjava.io.RandomAccessFile;5 importjava.nio.ByteBuffer;6 importjava.nio.channels.FileChannel;7 importjava.nio.channels.FileChannel.MapMode;8

9 /**

10 *@authorzsm11 * @date 2017年3月3日 上午10:23:5312 */

13 public classTest {14 public static voidmain(String[] args)15 throwsNoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {16 longstartTime, 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) throwsIOException {32

33 RandomAccessFile randomAccessFileOutput = new RandomAccessFile(srcFilePath, "rw");34 FileChannel inChannel =randomAccessFileOutput.getChannel();35

36 longdevsn, gpstime;37 doublelongitude, latitude;38 long dataCount = 0;39

40 ByteBuffer byteBuffer = ByteBuffer.allocateDirect((int) randomAccessFileOutput.length());//35ms41 //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 returndataCount;57 }58

59 //22ms

60 public static long readFromMMFile(String srcFilePath) throwsIOException {61 RandomAccessFile randomAccessFileOutput = new RandomAccessFile(srcFilePath, "rw");62 FileChannel inChannel =randomAccessFileOutput.getChannel();63

64 longdevsn, gpstime;65 doublelongitude, 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 returndataCount;79 }80

81 }

View Code

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值