首页 > 代码库 > Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)
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类进行分配(见下节)。通常来说,后者的读写性能比前者的好,但是后者的分配比前者慢,特别是在数据量大的情况下差别更明显。
比较:
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:16070 access_direct:13571 72 分配性能测试:73 allocate_nondirect:23174 allocate_direct:644
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 zsm11 * @date 2017年3月3日 上午10:23:5312 */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 block26 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());// 45ms41 // ByteBuffer byteBuffer = ByteBuffer.allocate((int) randomAccessFileOutput.length());// 46ms42 // while (inChannel.read(byteBuffer) > 0) {// 加上wihle后,分别用时77ms,120ms43 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 // 22ms60 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 }
前两者要45ms左右,而内存映射文件只要22ms左右。
Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。