目录_Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)
简单总结:
1、内存映射文件
读文件时候一般要两次复制:从磁盘复制到内核空间再复制到用户空间,内存映射文件避免了第二次复制,且内存分配在内核空间,应用程序访问的就是操作系统的内核内存空间,因此极大提高了读取效率。写文件同理。
2、堆内存分配与直接内存分配:
Java申请空间时通常是从JVM堆内存分配的,即 ByteBuffer.allocate(int capacity) ,但其实还可以直接从物理内存(用户空间内存?)分配,即 ByteBuffer.allocateDirect(int capacity) ,后者其实调用了Unsafe类进行分配(见下节)。后者的分配原理是这样的:使用Native函数库直接分配堆外内存,通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,从而避免了在java堆和Native堆之间复制数据的开销。
通常来说,由于后者避免了数据在堆外内存和JVM堆内存间的复制,所以读写性能比前者的好,但是后者的分配比前者慢,特别是在数据量大的情况下差别更明显。此外,直接内存常被用来扩展可用的内存区域。
比较:
 class DirectMemory {
     // 分配堆内存
     public static void bufferAccess() {
         long startTime = System.currentTimeMillis();
         ByteBuffer b = ByteBuffer.allocate(500);
         for (int i = 0; i < 1000000; i++) {
             for (int j = 0; j < 99; j++)
                 b.putInt(j);
             b.flip();
             for (int j = 0; j < 99; j++)
                 b.getInt();
             b.clear();
         }
         long endTime = System.currentTimeMillis();
         System.out.println("access_nondirect:" + (endTime - startTime));
     }
     // 直接分配内存
     public static void directAccess() {
         long startTime = System.currentTimeMillis();
         ByteBuffer b = ByteBuffer.allocateDirect(500);
         for (int i = 0; i < 1000000; i++) {
             for (int j = 0; j < 99; j++)
                 b.putInt(j);
             b.flip();
             for (int j = 0; j < 99; j++)
                 b.getInt();
             b.clear();
         }
         long endTime = System.currentTimeMillis();
         System.out.println("access_direct:" + (endTime - startTime));
     }
     public static void bufferAllocate() {
         long startTime = System.currentTimeMillis();
         for (int i = 0; i < 1000000; i++) {
             ByteBuffer.allocate(1000);
         }
         long endTime = System.currentTimeMillis();
         System.out.println("allocate_nondirect:" + (endTime - startTime));
     }
     public static void directAllocate() {
         long startTime = System.currentTimeMillis();
         for (int i = 0; i < 1000000; i++) {
             ByteBuffer.allocateDirect(1000);
         }
         long endTime = System.currentTimeMillis();
         System.out.println("allocate_direct:" + (endTime - startTime));
     }
     public static void main(String args[]) {
         System.out.println("访问性能测试:");
         bufferAccess();
         directAccess();
         System.out.println();
         System.out.println("分配性能测试:");
         bufferAllocate();
         directAllocate();
     }
 }
 //结果
 访问性能测试:
 access_nondirect:160
 access_direct:135
 分配性能测试:
 allocate_nondirect:231
 allocate_direct:644
3、Unsafe类
直接内存分配(allocateDirect)其实就是调用了sun.misc.Unsafe类来进行内存分配,Unsafe是sun.*API中的类,它不是J2SE中真正的一部份。
关于JVM对内存分配、直接内存分配、内存映射文件的一个测试示例:
(2684862条记录,每条记录包含4个long值,所有记录以二进制形式存储在文件中)
以上述三种方式读取每条记录(每种方式都是一次就分配足够的内存,直接内存分配、JVM内存分配、内存映射文件三者分别用时35ms、46ms、22ms):
package buaa.act.ucar.imtg.main; import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode; /**
* @author zsm
* @date 2017年3月3日 上午10:23:53
*/
public class Test {
public static void main(String[] args)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
long startTime, dataCount; try {
startTime = System.currentTimeMillis();
System.out.println("reading");
dataCount = readFromMMFile("F:/gps data/2016-11-11 18087 60399647/beijing_0900-1500_2684862.binary");
System.out.printf("reading %d data,time used:%d ms \n", dataCount,
(System.currentTimeMillis() - startTime));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } public static long readFromFile(String srcFilePath) throws IOException { RandomAccessFile randomAccessFileOutput = new RandomAccessFile(srcFilePath, "rw");
FileChannel inChannel = randomAccessFileOutput.getChannel(); long devsn, gpstime;
double longitude, latitude;
long dataCount = 0; ByteBuffer byteBuffer = ByteBuffer.allocateDirect((int) randomAccessFileOutput.length());// 35ms
// ByteBuffer byteBuffer = ByteBuffer.allocate((int) randomAccessFileOutput.length());// 46ms
while (inChannel.read(byteBuffer) > 0) {
byteBuffer.flip();// 进入read模式
while (byteBuffer.hasRemaining()) {
devsn = byteBuffer.getLong();
gpstime = byteBuffer.getLong();
longitude = Double.longBitsToDouble(byteBuffer.getLong());
latitude = Double.longBitsToDouble(byteBuffer.getLong());
// System.out.println(devsn + " " + gpstime + " " + longitude + " " + latitude);
dataCount++;
}
byteBuffer.clear();// 进入write模式
}
inChannel.close();
randomAccessFileOutput.close();
return dataCount;
} // 22ms
public static long readFromMMFile(String srcFilePath) throws IOException {
RandomAccessFile randomAccessFileOutput = new RandomAccessFile(srcFilePath, "rw");
FileChannel inChannel = randomAccessFileOutput.getChannel(); long devsn, gpstime;
double longitude, latitude;
long dataCount = 0;
ByteBuffer byteBuffer = inChannel.map(MapMode.READ_ONLY, 0, randomAccessFileOutput.length());
while (byteBuffer.hasRemaining()) {
devsn = byteBuffer.getLong();
gpstime = byteBuffer.getLong();
longitude = Double.longBitsToDouble(byteBuffer.getLong());
latitude = Double.longBitsToDouble(byteBuffer.getLong());
// System.out.println(devsn + " " + gpstime + " " + longitude + " " + latitude);
dataCount++;
}
inChannel.close();
randomAccessFileOutput.close();
return dataCount;
} }
目录_Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)的更多相关文章
- java中内存分配策略及堆和栈的比较
		Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ... 
- 栈 堆  stack heap  堆内存 栈内存  内存分配中的堆和栈 掌握堆内存的权柄就是返回的指针 栈是面向线程的而堆是面向进程的。 new/delete and malloc/ free 指针与内存模型
		小结: 1.栈内存 为什么快? Due to this nature, the process of storing and retrieving data from the stack is ver ... 
- 内存分配(new/delete,malloc/free,allocator,内存池)
		以下来源http://www.cnblogs.com/JCSU/articles/1051826.html 程序员们经常编写内存管理程序,往往提心吊胆.如果不想触雷,唯一的解决办法就是发现所有潜伏的地 ... 
- 内存分配方式,堆区,栈区,new/delete/malloc/free
		1.内存分配方式 内存分配方式有三种: [1]从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量,static变量. [2]在栈上创建.在执行函数时 ... 
- C/C++ 内存分配方式,堆区,栈区,new/delete/malloc/free
		内存分配方式 内存分配方式有三种: [1] 从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量, static 变量. [2] 在栈上创建.在执行函 ... 
- JVM中内存分配策略及堆和栈的比较
		最近愈发对JVM底层的运行 原理产生了兴趣,遂查阅相关资料以备忘. 内存分配策略 根据编译原理的观点,程序运行时的内存分配,有三种策略,分别为静态的.堆式的.栈式的. 静态存储分配指的是在编译时就能确 ... 
- 关于c语言内存分配,malloc,free,和段错误,内存泄露
		1. C语言的函数malloc和free (1) 函数malloc和free在头文件<stdlib.h>中的原型及参数 void * malloc(size_t size ... 
- C++内存分配方式(——选自:C++内存管理技术内幕)
		C++内存分配的区: 1.栈:程序运行时分配的,局部变量,以及传入的参数等存储的地方,在程序结束的时候会回收 2.堆:new分配,由delete释放 3.自由存储区:malloc分配 4.全局/静态存 ... 
- C++_类和动态内存分配2-改进后的String类
		添加前面介绍过的复制构造函数和赋值运算符,使类能够正确管理类对象使用的内存. 知道对象何时被创建和释放. =================================== 修订后的默认构造函数 ... 
- .NET的堆和栈01,基本概念、值类型内存分配
		当我们对.NET Framework的一些基本面了解之后,实际上,还是很有必要了解一些更底层的知识.比如.NET Framework是如何进行内存管理的,是如何垃圾回收的......这样,我们才能写出 ... 
随机推荐
- win  7 下合并多个表格
			首先我这里从服务器上下载了一大堆的表格 分类放好之后 这里我们需要把每一类的表格合并成一张表格 这里我们使用win 7下的copy的命令 这里我的表格的格式是csv 使用cmd 我们先cd到你的表格的 ... 
- docker容器网络通信原理分析
			概述 自从docker容器出现以来,容器的网络通信就一直是大家关注的焦点,也是生产环境的迫切需求.而容器的网络通信又可以分为两大方面:单主机容器上的相互通信和跨主机的容器相互通信.而本文将分别针对这两 ... 
- [转载]关于generate用法的总结【Verilog】
			转载自http://www.cnblogs.com/nanoty/archive/2012/11/13/2768933.html Abtract generate语句允许细化时间(Elaboratio ... 
- [svc]centos6使用chkconfig治理服务和其原理
			centos6开机启动级别 $ cat /etc/inittab ... # 0 - halt (Do NOT set initdefault to this) # 1 - Single user m ... 
- 【Unity】10.1 类人动画的导入和设置
			分类:Unity.C#.VS2015 创建日期:2016-05-02 一.制作或购买类人模型 为了充分使用 Mecanim 类人动画系统和类人动画的动画重定位功能,需要先使用其他3D建模软件(例如3d ... 
- Binlog中最容易踩到的坑
			MySQL高可用架构中,主库复制是非常常见的一种. 当主库宕机后,可以提升一个从库作为新的主库,保证服务可用性:同时可以通过扩展从库,提高整个集群的QPS. 在主从复制架构下,MySQL通过binlo ... 
- 四步法分析定位生产环境下MySQL上千条SQL中的问题所在
			第一步:通过以下两种方式之一来打开慢查询功能 (1)方式一:通过修改mysql的my.cnf文件 如果是5.0或5.1等版本需要增加以下选项: log-slow-queries="mysql ... 
- 每日英语:The Delicate Protocol Of Hugging
			I'm not a hugger. When I see a registered personal-space invader coming my way at a party, the music ... 
- App store 应用审核由于 IPv6 网络问题被拒的一点分析
			App store 应用审核由于 IPv6 网络问题被拒的一点分析 六月以后陆续有一些软件提交市场的时候被拒了,症状基本就是无法登陆啥的.我们公司的应用也未能幸免. 很多同学也想了不少办法,申诉. ... 
- Python 操作redis有序集合(sorted set)
			#coding:utf8 import redis r =redis.Redis(host=") 1.Zadd Zadd 命令用于将一个或多个成员元素及其分数值加入到有序集当中.如果某个成员 ... 
