1 来源

  • 来源:《Java虚拟机 JVM故障诊断与性能优化》——葛一鸣
  • 章节:第三章

本文是第三章的一些笔记整理。

2 GC日志:-Xlog:gc

要打印GC日志的话,可以加上-Xlog:gc参数(JDK8及以下请使用-XX:+PrintGC),开启GC打印后,每次GC就会打印如下的日志(OpenJDK11 -Xlog:gc):

[0.126s][info][gc] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 25M->0M(502M) 1.902ms
[0.205s][info][gc] GC(1) Pause Young (Normal) (G1 Evacuation Pause) 300M->0M(502M) 4.174ms
[0.236s][info][gc] GC(2) Pause Young (Normal) (G1 Evacuation Pause) 300M->0M(502M) 2.067ms
[0.268s][info][gc] GC(3) Pause Young (Normal) (G1 Evacuation Pause) 300M->0M(502M) 2.362ms

其中开头的时间表示发生GC的时刻,25M->0M(502M)表示:

  • GC前,堆使用量为25M
  • GC后,堆使用量为0M
  • 堆空间总和约为502M

末尾的时间表示本次GC的耗时。

另外如果需要更加详细的参数,可以使用-Xlog:gc*JDK8及以下请使用-XX:+PrintGCDetails),比如下面是一部分的GC日志(-Xlog:gc*):

[0.137s][info][gc,start     ] GC(0) Pause Young (Normal) (G1 Evacuation Pause)
[0.138s][info][gc,task      ] GC(0) Using 10 workers of 10 for evacuation
[0.147s][info][gc,phases    ] GC(0)   Pre Evacuate Collection Set: 0.0ms
[0.147s][info][gc,phases    ] GC(0)   Evacuate Collection Set: 8.8ms
[0.147s][info][gc,phases    ] GC(0)   Post Evacuate Collection Set: 0.2ms
[0.147s][info][gc,phases    ] GC(0)   Other: 0.8ms
[0.147s][info][gc,heap      ] GC(0) Eden regions: 25->0(300)
[0.147s][info][gc,heap      ] GC(0) Survivor regions: 0->1(4)
[0.147s][info][gc,heap      ] GC(0) Old regions: 0->0
[0.147s][info][gc,heap      ] GC(0) Humongous regions: 0->0
[0.147s][info][gc,metaspace ] GC(0) Metaspace: 6633K->6633K(1056768K)
[0.147s][info][gc           ] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 25M->0M(502M) 9.878ms
[0.147s][info][gc,cpu       ] GC(0) User=0.05s Sys=0.00s Real=0.01s
  • 行首的时间:事件发生的时刻
  • GC(0):这是第1次GC,接着会有GC(1)GC(2)
  • Pause Young(Normal):这次GC回收了新生代
  • Using 10 workers:使用10个工作线程
  • Pre Evacuate Collection Set/Evacuate Collection Set/Post Evacuate/Other:表示G1垃圾回收标记,清除算法不同阶段所花费的时间
  • Eden/Survivor/Old/Humongous/Metaspace:分别表示eden区存活区老年区巨型对象区(就是很大很大的对象所在的区域)、元数据区GC前后的大小
  • 25M-0M(502M)GC前堆占用25MGC后为0M,可用堆空间为502M
  • User/Sys/Real:分别表示用户态CPU耗时系统CPU耗时GC真实经历时间

如果想查看更全面的堆信息,可以使用Visual VM,将在后续文章中叙述。

另外如果需要将日志持久化,可以使用-Xlog:gc:gc.log

3 系统参数打印

参数-XX:+PrintVMOptinos可以打印运行时接收到的显式参数,而-XX:+PrintCommandLineFlags可以打印传递给JVM的隐式与显式参数:

另外一个参数是-XX:+PrintFlagsFinal,会打印所有系统参数的值(数量很多):

4 堆参数

4.1 最大堆与初始堆参数

Java进程启动时,虚拟机就会分配一块初始堆空间,可以使用参数-Xms指定这块空间的初始化大小。一般来说虚拟机会尽可能维持在初始堆空间范围内运行,但是如果初始堆空间耗尽,虚拟机会将堆空间进行扩展,扩展上限为最大堆空间,最大堆空间可以使用参数-Xmx指定。

来一段代码测试一下:

public class Main {public static void main(String[] args){printMemory();byte [] bytes = new byte[1*1024*1024];System.out.println("Allocate 1024 KB array");printMemory();bytes = new byte[4*1024*1024];System.out.println("Allocate 4096 KB array");printMemory();}public static void printMemory(){System.out.println();System.out.println("Max memory = " + Runtime.getRuntime().maxMemory() / 1024+ " KB");System.out.println("Free memory = "+Runtime.getRuntime().freeMemory()/1024+ " KB");System.out.println("Total memory = " + Runtime.getRuntime().totalMemory()/ 1024+ " KB");System.out.println();}
}

参数:

-Xmx20m
-Xms5m
-XX:+PrintCommandLineFlags
-Xlog:gc*
-XX:+UseSerialGC

输出:

-XX:InitialHeapSize=5242880 -XX:MaxHeapSize=20971520 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseSerialGC
[0.002s][info   ][gc] Using Serial
[0.002s][info   ][gc,heap,coops] Heap address: 0x00000000fec00000, size: 20 MB, Compressed Oops mode: 32-bit[0.110s][info   ][gc,start     ] GC(0) Pause Young (Allocation Failure)
[0.112s][info   ][gc,heap      ] GC(0) DefNew: 1664K->192K(1856K)
[0.112s][info   ][gc,heap      ] GC(0) Tenured: 0K->598K(4096K)
[0.112s][info   ][gc,metaspace ] GC(0) Metaspace: 6436K->6436K(1056768K)
[0.112s][info   ][gc           ] GC(0) Pause Young (Allocation Failure) 1M->0M(5M) 2.069ms
[0.112s][info   ][gc,cpu       ] GC(0) User=0.00s Sys=0.00s Real=0.01s
Max memory = 19840 KB
Free memory = 4797 KB
Total memory = 5952 KBAllocate 1024 KB arrayMax memory = 19840 KB
Free memory = 3773 KB
Total memory = 5952 KB[0.128s][info   ][gc,start     ] GC(1) Pause Young (Allocation Failure)
[0.129s][info   ][gc,start     ] GC(2) Pause Full (Allocation Failure)
[0.129s][info   ][gc,phases,start] GC(2) Phase 1: Mark live objects
[0.130s][info   ][gc,phases      ] GC(2) Phase 1: Mark live objects 1.366ms
[0.130s][info   ][gc,phases,start] GC(2) Phase 2: Compute new object addresses
[0.130s][info   ][gc,phases      ] GC(2) Phase 2: Compute new object addresses 0.235ms
[0.130s][info   ][gc,phases,start] GC(2) Phase 3: Adjust pointers
[0.131s][info   ][gc,phases      ] GC(2) Phase 3: Adjust pointers 0.624ms
[0.131s][info   ][gc,phases,start] GC(2) Phase 4: Move objects
[0.131s][info   ][gc,phases      ] GC(2) Phase 4: Move objects 0.042ms
[0.131s][info   ][gc             ] GC(2) Pause Full (Allocation Failure) 1M->1M(5M) 2.335ms
[0.131s][info   ][gc,heap        ] GC(1) DefNew: 1579K->0K(1856K)
[0.131s][info   ][gc,heap        ] GC(1) Tenured: 598K->1899K(4096K)
[0.131s][info   ][gc,metaspace   ] GC(1) Metaspace: 6624K->6624K(1056768K)
[0.131s][info   ][gc             ] GC(1) Pause Young (Allocation Failure) 2M->1M(5M) 3.636ms
[0.131s][info   ][gc,cpu         ] GC(1) User=0.00s Sys=0.01s Real=0.00s
Allocate 4096 KB arrayMax memory = 19840 KB
Free memory = 4087 KB
Total memory = 10116 KB[0.133s][info   ][gc,heap,exit   ] Heap
[0.133s][info   ][gc,heap,exit   ]  def new generation   total 1920K, used 44K [0x00000000fec00000, 0x00000000fee10000, 0x00000000ff2a0000)
[0.133s][info   ][gc,heap,exit   ]   eden space 1728K,   2% used [0x00000000fec00000, 0x00000000fec0b198, 0x00000000fedb0000)
[0.133s][info   ][gc,heap,exit   ]   from space 192K,   0% used [0x00000000fedb0000, 0x00000000fedb0000, 0x00000000fede0000)
[0.133s][info   ][gc,heap,exit   ]   to   space 192K,   0% used [0x00000000fede0000, 0x00000000fede0000, 0x00000000fee10000)
[0.133s][info   ][gc,heap,exit   ]  tenured generation   total 8196K, used 5995K [0x00000000ff2a0000, 0x00000000ffaa1000, 0x0000000100000000)
[0.133s][info   ][gc,heap,exit   ]    the space 8196K,  73% used [0x00000000ff2a0000, 0x00000000ff87aed0, 0x00000000ff87b000, 0x00000000ffaa1000)
[0.133s][info   ][gc,heap,exit   ]  Metaspace       used 6640K, capacity 6723K, committed 7040K, reserved 1056768K
[0.133s][info   ][gc,heap,exit   ]   class space    used 590K, capacity 623K, committed 640K, reserved 1048576K

最大内存由-XX:MaxHeapSize指定,该值为-Xmx的值,也就是20 * 1024 * 1024,而打印的最大可用内存为20316160,比设定的值少,这是因为分配给堆的内存空间与实际可用的内存空间并不是同一个概念,由于GC的需要,虚拟机会对堆空间进行分区管理,不同的区会采用不同的回收算法,一些算法会使用空间换时间的策略,因此会存在损失,最终的结果是实际可用内存会浪费大小等于from/to的空间,从输出可以知道:

[0.139s][info][gc,heap,exit   ]   from space 192K,   0% used [0x00000000fedb0000, 0x00000000fedb0000, 0x00000000fede0000)

from的大小为192k,但是实际情况是最大可用内存19840k+from192k=20032k,并不是分配的内存20480k,这是因为虚拟机会对from/to进行对齐,将最大可用内存加上对齐后的from/to即得到分配的内存大小。

另外,打印显示,初始运行空闲内存4797k,分配一个1024k数组后,空闲内存为3773k,正好符合,接着分配4096k,因为内存不足,对堆空间进行扩展后再分配,扩展后的堆大小为10116k

在实际工作中,可以将-Xms-Xmx设置为相同,这样可以减少运行时的GC次数,提高性能。

4.2 新生代参数

-Xmn可以设置新生代的大小,设置一个较大的新生代会减小老年代的大小,这个参数堆GC有很大影响,一般设置为堆空间的1/3-1/4。参数-XX:SurvivorRatio,也就是幸存区比例,可用来设置eden区from/to区的比例,相当于:

-XX:SurvivorRatio=eden/from=eden/to

一个简单的例子如下:

public static void main(String[] args){byte [] b = null;for (int i = 0; i < 10; i++) {b = new byte[1*1024*1024] ;}
}

参数:

-Xmx20m
-Xms20m
-Xmn1m
-XX:SurvivorRatio=2
-Xlog:gc*
-XX:+UseSerialGC

输出:

[0.002s][info][gc] Using Serial
[0.002s][info][gc,heap,coops] Heap address: 0x00000000fec00000, size: 20 MB, Compressed Oops mode: 32-bit
[0.042s][info][gc,start     ] GC(0) Pause Young (Allocation Failure)
[0.044s][info][gc,heap      ] GC(0) DefNew: 512K->256K(768K)
[0.044s][info][gc,heap      ] GC(0) Tenured: 0K->172K(19456K)
[0.044s][info][gc,metaspace ] GC(0) Metaspace: 3871K->3871K(1056768K)
[0.044s][info][gc           ] GC(0) Pause Young (Allocation Failure) 0M->0M(19M) 1.617ms
[0.044s][info][gc,cpu       ] GC(0) User=0.01s Sys=0.00s Real=0.00s
[0.064s][info][gc,start     ] GC(1) Pause Young (Allocation Failure)
[0.065s][info][gc,heap      ] GC(1) DefNew: 767K->76K(768K)
[0.065s][info][gc,heap      ] GC(1) Tenured: 172K->425K(19456K)
[0.065s][info][gc,metaspace ] GC(1) Metaspace: 4518K->4518K(1056768K)
[0.065s][info][gc           ] GC(1) Pause Young (Allocation Failure) 0M->0M(19M) 0.870ms
[0.065s][info][gc,cpu       ] GC(1) User=0.00s Sys=0.00s Real=0.00s
[0.093s][info][gc,heap,exit ] Heap
[0.093s][info][gc,heap,exit ]  def new generation   total 768K, used 562K [0x00000000fec00000, 0x00000000fed00000, 0x00000000fed00000)
[0.093s][info][gc,heap,exit ]   eden space 512K,  94% used [0x00000000fec00000, 0x00000000fec79730, 0x00000000fec80000)
[0.093s][info][gc,heap,exit ]   from space 256K,  29% used [0x00000000fec80000, 0x00000000fec93260, 0x00000000fecc0000)
[0.093s][info][gc,heap,exit ]   to   space 256K,   0% used [0x00000000fecc0000, 0x00000000fecc0000, 0x00000000fed00000)
[0.093s][info][gc,heap,exit ]  tenured generation   total 19456K, used 10665K [0x00000000fed00000, 0x0000000100000000, 0x0000000100000000)
[0.093s][info][gc,heap,exit ]    the space 19456K,  54% used [0x00000000fed00000, 0x00000000ff76a630, 0x00000000ff76a800, 0x0000000100000000)
[0.093s][info][gc,heap,exit ]  Metaspace       used 6190K, capacity 6251K, committed 6528K, reserved 1056768K
[0.093s][info][gc,heap,exit ]   class space    used 535K, capacity 570K, committed 640K, reserved 1048576K

eden区from区的比值为2:1,因此eden区512K,总可用新生代大小为512K+256K=768K,新生代总大小为512K+256K+256K=1M,由于eden区无法容纳分配1MB数组,因此触发了新生代GC,所有数组分配在了老年代。

而如果使用-Xmn7m(其他参数保持不变),输出如下:

[0.003s][info][gc] Using Serial
[0.003s][info][gc,heap,coops] Heap address: 0x00000000fec00000, size: 20 MB, Compressed Oops mode: 32-bit
[0.096s][info][gc,start     ] GC(0) Pause Young (Allocation Failure)
[0.097s][info][gc,heap      ] GC(0) DefNew: 2684K->1752K(5376K)
[0.097s][info][gc,heap      ] GC(0) Tenured: 0K->0K(13312K)
[0.097s][info][gc,metaspace ] GC(0) Metaspace: 5929K->5929K(1056768K)
[0.097s][info][gc           ] GC(0) Pause Young (Allocation Failure) 2M->1M(18M) 1.350ms
[0.097s][info][gc,cpu       ] GC(0) User=0.00s Sys=0.00s Real=0.00s
[0.098s][info][gc,start     ] GC(1) Pause Young (Allocation Failure)
[0.099s][info][gc,heap      ] GC(1) DefNew: 4928K->1024K(5376K)
[0.099s][info][gc,heap      ] GC(1) Tenured: 0K->727K(13312K)
[0.099s][info][gc,metaspace ] GC(1) Metaspace: 5996K->5996K(1056768K)
[0.099s][info][gc           ] GC(1) Pause Young (Allocation Failure) 4M->1M(18M) 1.142ms
[0.099s][info][gc,cpu       ] GC(1) User=0.01s Sys=0.00s Real=0.00s
[0.100s][info][gc,start     ] GC(2) Pause Young (Allocation Failure)
[0.100s][info][gc,heap      ] GC(2) DefNew: 4180K->1024K(5376K)
[0.100s][info][gc,heap      ] GC(2) Tenured: 727K->728K(13312K)
[0.100s][info][gc,metaspace ] GC(2) Metaspace: 6008K->6008K(1056768K)
[0.100s][info][gc           ] GC(2) Pause Young (Allocation Failure) 4M->1M(18M) 0.190ms
[0.100s][info][gc,cpu       ] GC(2) User=0.00s Sys=0.00s Real=0.00s
[0.100s][info][gc,heap,exit ] Heap
[0.100s][info][gc,heap,exit ]  def new generation   total 5376K, used 4211K [0x00000000fec00000, 0x00000000ff300000, 0x00000000ff300000)
[0.100s][info][gc,heap,exit ]   eden space 3584K,  88% used [0x00000000fec00000, 0x00000000fef1cc00, 0x00000000fef80000)
[0.100s][info][gc,heap,exit ]   from space 1792K,  57% used [0x00000000ff140000, 0x00000000ff2402a0, 0x00000000ff300000)
[0.100s][info][gc,heap,exit ]   to   space 1792K,   0% used [0x00000000fef80000, 0x00000000fef80000, 0x00000000ff140000)
[0.100s][info][gc,heap,exit ]  tenured generation   total 13312K, used 728K [0x00000000ff300000, 0x0000000100000000, 0x0000000100000000)
[0.100s][info][gc,heap,exit ]    the space 13312K,   5% used [0x00000000ff300000, 0x00000000ff3b61f8, 0x00000000ff3b6200, 0x0000000100000000)
[0.100s][info][gc,heap,exit ]  Metaspace       used 6034K, capacity 6091K, committed 6272K, reserved 1056768K
[0.100s][info][gc,heap,exit ]   class space    used 518K, capacity 538K, committed 640K, reserved 1048576K

此参数下,eden区有足够的空间,所有数组分配在eden区,但是不足以预留10M空间,因此产生了GC,每次申请空间也废弃了上一次申请的空间,在新生代GC中有效回收了这些内存,最后的结果是所有内存分配都在新生代进行,只是在GC过程中部分新生代对象晋升到了老年代。

再次增大新生代,使用-Xmn15m -XX:SurvivorRatio=8(其他参数不变),输出如下:

[0.003s][info][gc] Using Serial
[0.003s][info][gc,heap,coops] Heap address: 0x00000000fec00000, size: 20 MB, Compressed Oops mode: 32-bit
start
[0.097s][info][gc,start     ] GC(0) Pause Young (Allocation Failure)
[0.099s][info][gc,heap      ] GC(0) DefNew: 11416K->1471K(13696K)
[0.099s][info][gc,heap      ] GC(0) Tenured: 0K->294K(5312K)
[0.099s][info][gc,metaspace ] GC(0) Metaspace: 6103K->6103K(1056768K)
[0.099s][info][gc           ] GC(0) Pause Young (Allocation Failure) 11M->1M(18M) 2.322ms
[0.099s][info][gc,cpu       ] GC(0) User=0.00s Sys=0.00s Real=0.01s
end
[0.099s][info][gc,heap,exit ] Heap
[0.099s][info][gc,heap,exit ]  def new generation   total 13696K, used 2934K [0x00000000fec00000, 0x00000000ffad0000, 0x00000000ffad0000)
[0.099s][info][gc,heap,exit ]   eden space 12224K,  11% used [0x00000000fec00000, 0x00000000fed6d908, 0x00000000ff7f0000)
[0.099s][info][gc,heap,exit ]   from space 1472K,  99% used [0x00000000ff960000, 0x00000000ffacfff8, 0x00000000ffad0000)
[0.099s][info][gc,heap,exit ]   to   space 1472K,   0% used [0x00000000ff7f0000, 0x00000000ff7f0000, 0x00000000ff960000)
[0.099s][info][gc,heap,exit ]  tenured generation   total 5312K, used 294K [0x00000000ffad0000, 0x0000000100000000, 0x0000000100000000)
[0.099s][info][gc,heap,exit ]    the space 5312K,   5% used [0x00000000ffad0000, 0x00000000ffb19960, 0x00000000ffb19a00, 0x0000000100000000)
[0.099s][info][gc,heap,exit ]  Metaspace       used 6164K, capacity 6251K, committed 6528K, reserved 1056768K
[0.099s][info][gc,heap,exit ]   class space    used 532K, capacity 570K, committed 640K, reserved 1048576K

可以看到新生代使用15M空间,eden区占了12288K,完全满足了10MB需要,并没有发生GC(日志的GC只是在for循环结束后产生的,一次性回收了10M)。

实际工作中,应根据系统的特点,做合理的设置,基本策略是:

  • 尽可能将对象预留在新生代
  • 减少老年代GC次数

另外,可以使用-XX:NewRatio=老年代/新生代指定新生代和老年代的比例,比如使用参数:

-Xmx20m
-Xms20m
-XX:NewRatio=2
-Xlog:gc*
-XX:+UseSerialGC

输出:

[0.005s][info][gc] Using Serial
[0.005s][info][gc,heap,coops] Heap address: 0x00000000fec00000, size: 20 MB, Compressed Oops mode: 32-bit
[0.096s][info][gc,start     ] GC(0) Pause Young (Allocation Failure)
[0.097s][info][gc,heap      ] GC(0) DefNew: 4852K->639K(6144K)
[0.097s][info][gc,heap      ] GC(0) Tenured: 0K->1112K(13696K)
[0.097s][info][gc,metaspace ] GC(0) Metaspace: 5905K->5905K(1056768K)
[0.097s][info][gc           ] GC(0) Pause Young (Allocation Failure) 4M->1M(19M) 1.413ms
[0.097s][info][gc,cpu       ] GC(0) User=0.00s Sys=0.00s Real=0.00s
[0.098s][info][gc,start     ] GC(1) Pause Young (Allocation Failure)
[0.099s][info][gc,heap      ] GC(1) DefNew: 5920K->0K(6144K)
[0.099s][info][gc,heap      ] GC(1) Tenured: 1112K->2776K(13696K)
[0.099s][info][gc,metaspace ] GC(1) Metaspace: 5970K->5970K(1056768K)
[0.099s][info][gc           ] GC(1) Pause Young (Allocation Failure) 6M->2M(19M) 1.129ms
[0.099s][info][gc,cpu       ] GC(1) User=0.00s Sys=0.01s Real=0.00s
[0.100s][info][gc,heap,exit ] Heap
[0.100s][info][gc,heap,exit ]  def new generation   total 6144K, used 2238K [0x00000000fec00000, 0x00000000ff2a0000, 0x00000000ff2a0000)
[0.100s][info][gc,heap,exit ]   eden space 5504K,  40% used [0x00000000fec00000, 0x00000000fee2f690, 0x00000000ff160000)
[0.100s][info][gc,heap,exit ]   from space 640K,   0% used [0x00000000ff160000, 0x00000000ff160398, 0x00000000ff200000)
[0.100s][info][gc,heap,exit ]   to   space 640K,   0% used [0x00000000ff200000, 0x00000000ff200000, 0x00000000ff2a0000)
[0.100s][info][gc,heap,exit ]  tenured generation   total 13696K, used 2776K [0x00000000ff2a0000, 0x0000000100000000, 0x0000000100000000)
[0.100s][info][gc,heap,exit ]    the space 13696K,  20% used [0x00000000ff2a0000, 0x00000000ff556250, 0x00000000ff556400, 0x0000000100000000)
[0.100s][info][gc,heap,exit ]  Metaspace       used 5998K, capacity 6091K, committed 6272K, reserved 1056768K
[0.100s][info][gc,heap,exit ]   class space    used 517K, capacity 538K, committed 640K, reserved 1048576K

堆大小为20M,新生代和老年代的比为1:2,因此新生代大小约为7M,老年代为13M,分配1M时,由于from/to空间不足,导致两个1MB的数组进入了老年代。

4.3 堆溢出处理

如果在Java程序运行过程中,堆空间不足,会抛出内存溢出错误,也就是常见的OOM。想要分析原因,可以使用参数-XX:+HeapDumpOnOutOfMemoryError,可以在内存溢出时导出整个堆的信息,配合使用的还有-XX:HeapDumpPath,指定导出堆的存放路径,例子如下:

public static void main(String[] args){List<byte[]> list = new ArrayList<>();for (int i = 0; i < 25; i++) {list.add(new byte[1*1024*1024]);}
}

参数:

-Xmx20m
-Xms5m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=out.dump

例子分配了25M的内存,但是堆只有20M,会抛出OOM,并且文件保存到out.dump中,注意该文件是二进制文件,需要使用专业的工具(如MAT等)查看。

5 非堆参数

5.1 方法区

JDK8开始,永久区被移除,使用了新的元数据区来存放类的元数据,默认情况下,元数据区受系统可用内存的限制,但是仍然可以使用-XX:MaxMetaspaceSize指定永久区的最大可用值。

5.2 栈

栈是每个线程私有的空间,可以使用-Xss指定线程的栈大小,具体在笔者之前的文章中。

5.3 直接内存

直接内存跳过了Java堆,可以使得程序直接访问原生堆空间,在一定程度上加快了内存空间的访问速度。最大可用直接内存可以使用-XX:MaxDirectMemorySize设置,如果不设置,默认为最大堆空间,即-Xmx的值,当直接内存使用量到达最大值时,会触发GC,如果GC后不能有效释放足够的空间,直接内存依然会引起系统的OOM

下面测试一下直接内存与堆的速度:

public class Main {public static final int count = 1000000;public static void directAccess(){long start = System.currentTimeMillis();ByteBuffer b = ByteBuffer.allocateDirect(500);for(int i=0;i<count;++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 end = System.currentTimeMillis();System.out.println("Direct access: "+(end-start)+" ms");}public static void bufferAccess(){long start = System.currentTimeMillis();ByteBuffer b = ByteBuffer.allocate(500);for(int i=0;i<count;++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 end = System.currentTimeMillis();System.out.println("Buffer access: "+(end-start)+" ms");}public static void main(String[] args){directAccess();bufferAccess();directAccess();bufferAccess();}
}

输出(不带任何参数):

Direct access: 167 ms
Buffer access: 70 ms
Direct access: 176 ms
Buffer access: 67 ms

直接内存的访问速度要快于堆内存,但是有一个缺点就是申请的时候速度慢:

public static void directAllocate(){long start = System.currentTimeMillis();for (int i = 0; i < count; i++) {ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1000);}long end = System.currentTimeMillis();System.out.println("Direct allocate: "+(end-start)+" ms");
}public static void bufferAllocate(){long start = System.currentTimeMillis();for (int i = 0; i < count; i++) {ByteBuffer byteBuffer = ByteBuffer.allocate(1000);}long end = System.currentTimeMillis();System.out.println("Buffer allocate: "+(end-start)+" ms");
}public static void main(String[] args){directAllocate();bufferAllocate();directAllocate();bufferAllocate();
}

输出:

Direct allocate: 867 ms
Buffer allocate: 287 ms
Direct allocate: 676 ms
Buffer allocate: 208 ms

简单来说,直接内存适合申请次数较少、访问较频繁的场合,如果需要频繁申请内存空间,并不适合使用直接内存。

JVM学习笔记(三):JVM基本参数相关推荐

  1. java之jvm学习笔记十三(jvm基本结构)

    欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完 ...

  2. JVM学习笔记之-JVM性能监控-JVM监控及诊断工具-GUI方式-Visual VM-JProfiler-Arthas

    00-谈GUI工具前的补充 补充1:内存泄漏 内存泄漏的理解与分类 何为内存泄漏( memory leak) 可达性分析算法来判断对象是否是不再使用的对象,本质都是判断一个对象是否还被引用.那么对于这 ...

  3. JVM学习笔记之-JVM性能监控-JVM监控及诊断工具-命令行方式

    性能优化的步骤 第1步(发现问题):性能监控 一种以非强行或者入侵方式收集或查看应用运营性能数据的活动. 监控通常是指一种在生产.质量评估或者开发环境下实施的带有预防或主动性的活动. 当应用相关干系人 ...

  4. JVM 学习笔记 1. JVM 运行模型

    目录 JVM 启动流程 JVM 基本结构 内存模型 虚拟机的运行方式 1. JVM 启动流程 如下图所示: 2. JVM 基本结构 两幅经典的模型图: 其中: PC寄存器:每个线程都拥有一个PC寄存器 ...

  5. tensorflow(神经网络)学习笔记(三)之调参数实战(笔记)

    tensorboard # 指定目录 LOG_DIR = '.' run_label = 'run_vgg_tensorboard_fine_tune' run_dir = os.path.join( ...

  6. 【JVM学习笔记】内存回收与内存回收算法 就哪些地方需要回收、什么时候回收、如何回收三个问题进行分析和说明

    目录 一.相关名词解释 垃圾收集常用名词 二.哪些地方需要回收 本地方法栈.虚拟机栈.程序计数器 方法区 Java堆 三.什么时候回收 1. 内存能否被回收 内存中的引用类型 引用计数算法 可达性分析 ...

  7. jvm学习笔记(三)

    jvm学习笔记(三) 文章目录 jvm学习笔记(三) 1.全部笔记链接 2.堆 2.1堆的划分 使用JVM参数查看划分 Hotspot堆内存划分图(JDK8之前) 2.2 GC对堆的回收 GC的种类 ...

  8. JVM学习笔记(四)

    JVM学习笔记(四) 文章目录 JVM学习笔记(四) 笔记链接 1.GC算法 1.1GC-判断对象是否可回收 1.1.1 引用计数法 1.1.1 可达性分析 1.2GC-回收算法 标记清除法(Mark ...

  9. JVM学习笔记-01-JVM的学习方式

    JVM学习笔记-01-JVM的学习方式 文章目录 JVM学习笔记-01-JVM的学习方式 JVM探究 最新JVM教程IDEA版[Java面试速补篇]-01-JVM的学习方式 JVM探究 请你谈谈对JV ...

  10. 【JVM 学习笔记 05】:JVM性能调优工具的使用和优化案例

    [JVM 学习笔记 05]:JVM性能调优工具的使用 1. 使用 jstat(命令行工具) 查看线上系统的JVM运行状况 1.1 常用命令 1.2 使用技巧 1.2.1 随着系统运行,每秒钟会在年轻代 ...

最新文章

  1. 个简单C++程序反汇编解析 (Rev. 3)
  2. C++中的模板展开问题
  3. Python预测2020高考分数和录取情况
  4. 13万张表+数亿行代码,迁移只需数小时,还是异构数据库
  5. 微软称伊朗国家黑客攻击美国国防技术公司
  6. Oracle ITL(Interested Transaction List)理解
  7. 【贪心】LeetCode 3. Longest Substring Without Repeating Characters
  8. C语言:用条件运算符的嵌套完成此题。学习成绩=90分的学生用A表示,70-89的学生用B表示,60-79的学生用表示,低于60分的学生用D表示
  9. 了解为什么要使用微服务!
  10. 杨辉三角c语言if 编程,杨辉三角_用c语言怎么编程
  11. 网易云音乐推荐系统特训_笔记
  12. 大智慧公式系统:指标公式
  13. syscall 系统调用陷入_MIPS中的异常处理和系统调用【转】-阿里云开发者社区
  14. linux内存硬件检测工具下载,极品内存检测工具(Memtest86)
  15. photoshop设置A4纸张大小
  16. matlab如何以矩阵形式读取TXT格式大量带分隔符号的实验数据
  17. 罗克韦尔AB PLC 通过RSLinx Classic与PLC建立通信的具体方法步骤
  18. CyclicBarrier: 循环栅栏
  19. Linux并行执行权限,如何在Linux中使用flock控制程序的异步执行
  20. 策略模式——多种发票上传实现案例

热门文章

  1. Debian deb文件打包及例程
  2. @Import注解与@Bean注解区别
  3. MySQL(InnoDB剖析):29---全文检索(倒排索引、全文索引/全文检索)
  4. 湘江新区:金融活水赋能实体经济
  5. 生产线清洁机器人在工作中学习
  6. 京华科讯虚拟化助推移动办公
  7. babun:A Windows shell you will love!
  8. 面试中出现这些信号,表明你面试通过了
  9. Node.js 16 生命周期 结束日期提前
  10. 【英语】本周做了点啥呢?