ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

JVM详解(七)——直接内存

2021-10-21 22:33:25  阅读:103  来源: 互联网

标签:null String System 详解 static 内存 JVM 直接


一、概述

1、介绍

  直接内存,不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。是Java堆直接向系统申请的内存区间。
  来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存。通常,访问直接内存的速度会优于Java堆,即读写性能高。因此处于性能考虑,读写频繁的场合可能会考虑使用直接内存。Java的NIO库允许Java程序使用直接内存,用于数据缓冲区。

IO NIO
byte[] / char[] Buffer
面向流(Stream) 面向缓冲区(Channel)
阻塞 非阻塞

  代码示例:IO与NIO、查看直接内存的占用与释放

 1 public class BufferTest {
 2     // 1GB
 3     private static final int BUFFER = 1024 * 1024 * 1024;
 4 
 5     public static void main(String[] args) {
 6         // 直接分配本地内存空间
 7         ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
 8         System.out.println("直接内存分配完毕,请求指示!");
 9 
10         Scanner scanner = new Scanner(System.in);
11         scanner.next();
12 
13         System.out.println("直接内存开始释放!");
14         byteBuffer = null;
15         
16         System.gc();
17         scanner.next();
18     }
19 }

  通过任务管理器,以及进程id,都可以看到java.exe占用了1G的内存。

2、使用本地内存读写

  通常,访问直接内存的速度会优于Java堆,即读写性能高。
  读写文件,需要与磁盘交互,需要由用户态切换到内核态,在内核态时,需要内存如图的操作。使用IO,如图,这里需要两份内存存储重复数据,效率低。非直接缓冲区:

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

  代码示例:使用本地内存读写数据的测试,验证直接缓冲区的读写性能比IO高。

 1 public class BufferTest1 {
 2 
 3     private static final int _100Mb = 1024 * 1024 * 100;
 4 
 5     public static void main(String[] args) {
 6         long sum = 0;
 7 
 8         String src = "F:\\后会无期.mkv";
 9 
10         for (int i = 0; i < 3; i++) {
11             String dest = "F:\\后会无期_" + i + ".mkv";
12 
13             // 非直接缓冲区 IO
14             // sum += io(src,dest); // 54540
15             // 直接缓冲区 NIO
16             sum += directBuffer(src, dest); // 49619
17         }
18 
19         System.out.println("总花费的时间为:" + sum);
20     }
21 
22     private static long directBuffer(String src, String dest) {
23         long start = System.currentTimeMillis();
24 
25         FileChannel inChannel = null;
26         FileChannel outChannel = null;
27         try {
28             inChannel = new FileInputStream(src).getChannel();
29             outChannel = new FileOutputStream(dest).getChannel();
30 
31             ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_100Mb);
32             while (inChannel.read(byteBuffer) != -1) {
33                 byteBuffer.flip(); // 修改为读数据模式
34                 outChannel.write(byteBuffer);
35                 byteBuffer.clear(); // 清空
36             }
37         } catch (IOException e) {
38             e.printStackTrace();
39         } finally {
40             if (inChannel != null) {
41                 try {
42                     inChannel.close();
43                 } catch (IOException e) {
44                     e.printStackTrace();
45                 }
46             }
47             if (outChannel != null) {
48                 try {
49                     outChannel.close();
50                 } catch (IOException e) {
51                     e.printStackTrace();
52                 }
53             }
54         }
55 
56         long end = System.currentTimeMillis();
57         return end - start;
58     }
59 
60     private static long io(String src, String dest) {
61         long start = System.currentTimeMillis();
62 
63         FileInputStream fis = null;
64         FileOutputStream fos = null;
65         try {
66             fis = new FileInputStream(src);
67             fos = new FileOutputStream(dest);
68             byte[] buffer = new byte[_100Mb];
69             while (true) {
70                 int len = fis.read(buffer);
71                 if (len == -1) {
72                     break;
73                 }
74                 fos.write(buffer, 0, len);
75             }
76         } catch (IOException e) {
77             e.printStackTrace();
78         } finally {
79             if (fis != null) {
80                 try {
81                     fis.close();
82                 } catch (IOException e) {
83                     e.printStackTrace();
84                 }
85             }
86             if (fos != null) {
87                 try {
88                     fos.close();
89                 } catch (IOException e) {
90                     e.printStackTrace();
91                 }
92             }
93         }
94         long end = System.currentTimeMillis();
95         return end - start;
96     }
97 }

3、直接内存OOM与大小的设置

  直接内存也可能导致OOM异常。由于直接内存在Java堆外,因此它的大小不会直接受限于-Xmx指定的最大堆大小。但是系统内存是有限的,Java堆和直接内存的总和应小于操作系统给出的最大内存。
  缺点:分配回收成本较高,不受JVM内存回收管理。
  直接内存大小可以通过MaxDirectMemorySize设置。默认情况与堆的最大值参数一致。
  代码示例:本地内存OOM,OutOfMemoryError:Direct buffer memory

 1 public class BufferTest2 {
 2     // 20MB
 3     private static final int BUFFER = 1024 * 1024 * 20;
 4 
 5     public static void main(String[] args) {
 6         ArrayList<ByteBuffer> list = new ArrayList<>();
 7 
 8         int count = 0;
 9         try {
10             while (true) {
11                 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
12 
13                 list.add(byteBuffer);
14                 count++;
15                 try {
16                     Thread.sleep(100);
17                 } catch (InterruptedException e) {
18                     e.printStackTrace();
19                 }
20             }
21         } finally {
22             System.out.println(count);
23         }
24     }
25 }
26 
27 // 181
28 // Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory

  代码示例:直接内存大小设置

 1 // -Xmx20m -XX:MaxDirectMemorySize=10m
 2 public class MaxDirectMemorySizeTest {
 3     private static final long _1MB = 1024 * 1024;
 4 
 5     public static void main(String[] args) throws IllegalAccessException {
 6         Field unsafeField = Unsafe.class.getDeclaredFields()[0];
 7         unsafeField.setAccessible(true);
 8 
 9         Unsafe unsafe = (Unsafe) unsafeField.get(null);
10         while (true) {
11             unsafe.allocateMemory(_1MB);
12         }
13     }
14 }

  简单理解:java process memory = java heap + native memory

标签:null,String,System,详解,static,内存,JVM,直接
来源: https://www.cnblogs.com/originator/p/15435505.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有