当前位置:网站首页>JVM上篇:内存与垃圾回收篇十--运行时数据区-直接内存
JVM上篇:内存与垃圾回收篇十--运行时数据区-直接内存
2022-07-27 05:01:00 【_院长大人_】
JVM上篇:内存与垃圾回收篇十–运行时数据区-直接内存
直接内存不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。
直接内存是在Java堆外的、直接向系统申请的内存区间。
来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存
public static ByteBuffer allocateDirect(int capacity) { return new DirectByteBuffer(capacity); }通常,访问直接内存的速度会优于Java堆。即读写性能高。
- 因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。
- Java的NIO库允许Java程序使用直接内存,用于数据缓冲区
1. 查看直接内存的占用与释放
代码示例
/** * IO NIO (New IO / Non-Blocking IO):非阻塞式 * byte[] / char[] Buffer * Stream Channel * * 查看直接内存的占用与释放 */
public class BufferTest {
private static final int BUFFER = 1024 * 1024 * 1024;//1GB
public static void main(String[] args){
//直接分配本地内存空间
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
System.out.println("直接内存分配完毕,请求指示!");
Scanner scanner = new Scanner(System.in);
scanner.next();
System.out.println("直接内存开始释放!");
byteBuffer = null;
System.gc();
scanner.next();
}
}
未启动程序时内存时的任务管理器

启动程序后分配了1g的直接内存的任务管理器
查看进程id


释放掉1g直接内存的任务管理器

程序关闭后的任务管理器

2. 非直接缓存与直接缓存
2.1 非直接缓存(BIO)
原来采用BIO的架构,在读写本地文件时,我们需要从用户态切换成内核态

2.2 直接缓存(NIO)
使用NIO时,如下图。操作系统划出的直接缓存区可以被Java代码直接访问,只有一份。NIO适合对大文件的读写操作

3. 使用本地内存读写数据的测试

测试代码
package com.atguigu.java;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class BufferTest1 {
private static final String TO = "C:\\Users\\eric\\Desktop\\test\\IOTest\\u盘备份.rar";
private static final int _100Mb = 1024 * 1024 * 100;
public static void main(String[] args) {
long sum = 0;
String src = "C:\\Users\\eric\\Desktop\\test\\IOTest\\u盘备份.rar";
for (int i = 0; i < 3; i++) {
String dest = "C:\\Users\\eric\\Desktop\\test\\IOTest\\u盘备份-"+i+".rar";
sum += io(src,dest);//54606
// sum += directBuffer(src,dest);//50244
}
System.out.println("总花费的时间为:" + sum );
}
private static long directBuffer(String src,String dest) {
long start = System.currentTimeMillis();
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
inChannel = new FileInputStream(src).getChannel();
outChannel = new FileOutputStream(dest).getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_100Mb);
while (inChannel.read(byteBuffer) != -1) {
byteBuffer.flip();//修改为读数据模式
outChannel.write(byteBuffer);
byteBuffer.clear();//清空
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long end = System.currentTimeMillis();
return end - start;
}
private static long io(String src,String dest) {
long start = System.currentTimeMillis();
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(src);
fos = new FileOutputStream(dest);
byte[] buffer = new byte[_100Mb];
while (true) {
int len = fis.read(buffer);
if (len == -1) {
break;
}
fos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long end = System.currentTimeMillis();
return end - start;
}
}
未使用本地内存

使用本地内存

结论:使用本地内存读写会快一些
4 直接内存OOM
- 直接内存也可能导致
OutofMemoryError异常 - 由于直接内存在Java堆外,因此它的大小不会直接受限于
-Xmx指定的最大堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存 - 直接内存的
缺点为:- 分配回收成本较高
- 不受JVM内存回收管理
- 直接内存大小可以通过
MaxDirectMemorySize设置 - 如果不指定,默认与堆的最大值-Xmx参数值一致
代码示例
/** * 本地内存的OOM: OutOfMemoryError: Direct buffer memory */
public class BufferTest2 {
private static final int BUFFER = 1024 * 1024 * 20;//20MB
public static void main(String[] args) {
ArrayList<ByteBuffer> list = new ArrayList<>();
int count = 0;
try {
while(true){
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
list.add(byteBuffer);
count++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
System.out.println(count);
}
}
}

4.1 ByteBuffer.allocateDirect(BUFFER)源码
ByteBuffer.allocateDirect(BUFFER)本质上是unsafe.allocateMemory(size)

4.2 直接通过 Unsafe 类申请本地内存
代码示例
/** * -Xmx20m -XX:MaxDirectMemorySize=10m */
public class MaxDirectMemorySizeTest {
private static final long _1MB = 1024 * 1024;
public static void main(String[] args) throws IllegalAccessException {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe)unsafeField.get(null);
while(true){
unsafe.allocateMemory(_1MB);
}
}
}
设置设置JVM 参数
-Xmx20m -XX:MaxDirectMemorySize=10m抛出 OOM 异常

5. JDK7与JDK8的JVM内存结构
可以理解Java程序进程所占的内存空间 = 本地内存 + 堆空间

边栏推荐
- 接口和抽象类/方法学习 demo
- MQ message queue is used to design the high concurrency of the order placing process, the generation scenarios and solutions of message squeeze, message loss and message repetition
- Typescript details
- Detailed explanation of mvcc and its principle
- MySQL storage engine and its differences
- File dialog box
- Jmeter 界面如何汉化?
- Event Summary - common summary
- Replication of df-gan experiment -- detailed steps of replication of dfgan and forwarding from remote port to local port using mobaxtem
- R-score reproduction R-Precision evaluation index quantitative text generation image r-score quantitative experiment whole process reproduction (R-Precision) quantitative evaluation experiment step on
猜你喜欢

树莓派输出PWM波驱动舵机

How to sinicize the JMeter interface?

Why is count (*) slow

标准对话框 QMessageBox

微淼联合创始人孙延芳:以合规为第一要义,做财商教育“正规军”

How does the TCP server handle multiple client connections on one port (one-to-one or one to many)

Plato Farm有望通过Elephant Swap,进一步向外拓展生态

【搜索】DFS之连通性模型 + 搜索顺序
![[error reporting]: cannot read properties of undefined (reading 'prototype')](/img/e4/528480610b9eed6028d7b3b87571e2.png)
[error reporting]: cannot read properties of undefined (reading 'prototype')

ssm框架整合
随机推荐
【Acwing】第61场周赛 题解
Dialog introduction
一道数学题,让芯片巨头亏了5亿美金
feign调用丢失请求头问题解决及原理分析
MQ message queue is used to design the high concurrency of the order placing process, the generation scenarios and solutions of message squeeze, message loss and message repetition
树莓派rtmp推流本地摄像头图像
static和final关键字 学习 demo练习
Constraints of MySQL table
File dialog box
OFDM 十六讲 2- OFDM and the DFT
How to test the payment process?
【无标题】按照一定的条件,对 i 进行循环累加。条件通常为循环数组的长度,当超过长度就停止循环。因为对象无法判断长度,所以通常搭配 Object.keys() 使用。\nforEach 一般认为是 普
树莓派输出PWM波驱动舵机
Solution: how to use bash batch command in win10
OFDM 16 lecture 2-ofdm and the DFT
Reproduce ssa-gan using the nine day deep learning platform
SVN使用详解
Standard dialog qmessagebox
安装Pygame
节流函数的demo——正则表达式匹配