一、JVM结构
二、运行时数据区分为以下几块空间:
- 1、堆(Heap):保存所有引用类型的真实数据,此区为共享区。
- 2、虚拟机栈(VM Stack):虚拟机栈描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。
方法调用时栈帧的动作:
- 3、方法区(Method Data Area):所有定义的方法的信息都保存在方法区之中,此区为共享区。
- 4、程序计数器:程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
- 5、本地方法栈:本地方法栈(Native MethodStacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。
三、JVM堆分为三块:
年轻代:新对象和没达到一定年龄的对象都在年轻代。
- 1、伊甸园区:所有的新对象都在伊甸园区产生。
2、存活区:存活区分为两块相等大小的区域S0和S1。伊甸园区中经过多次Minor GC后还存活的活跃对象将会晋升到存活区。
分为两块相同大小区域的目的:一块为了晋升,一块为了对象回收。这两块内存空间一定有一块是空的。
3、伸缩区:用于调整年轻代内存大小的缓冲区。
修改年轻代内存调整参数:
例如:-Xmx16g -Xms16g -XX:SurvivorRatio=6 -XX:+PrintGCDetails
设置Eden区和Survivor为“6:1:1”
年轻代GC(Minor GC)回收算法
描述:将伊甸园区的存活对象复制到存活区两块区域中空的那块,然后另外一块区域中的活跃对象根据其存活时间判断是保存到另块空间还是保存到老年代。然后清除不活跃对象,腾出空间。
在整个处理过程中,伊甸园区中保存的对象有可能大部分都临时对象,那么这样就有可能频繁的发生Minor GC,所以在HotSpot虚拟机中为了加快此空间的内存分配,采用了两种技术:
1、Bump-The-Pointer
缺点:多线程下有多个对象并行创建,就会影响性能。
2、TLAB(Thread-Local-Allocation Buffers)
老年代:被长时间使用的对象,老年代的内存空间比年轻代大。如果保存的对象超过了伊甸园区的内存大小,此对象将直接保存到老年代。
例如:-Xmx16g -Xms16g -XX:PretenureSizeThreshold=512k -XX:+PrintGCDetails
如果有超过512k的对象直接保存到老年代,这个对象不会再触发Minor GC。老年代GC(Major GC/Full GC)回收算法
- 1、标记-清除
先对老年代中不活跃对象进行标记,标记完成之后进行清除,不会对清除后的空间进行整理,会导致内存碎片化问题。 - 2、标记-压缩
先对老年代中不活跃对象进行标记,标记完成之后进行清除,清除之后再对空间碎片进行整理压缩。
- 1、标记-清除
永久代和元空间:永久代在JDK1.8之后被元空间替代。目的是将HotSpot与JRockit两个虚拟机标准统一。
永久代(JDK1.8以前):永久代是在堆内存中保存的,但是永久代不会被回收,例如:intern()产生的对象就不会被回收。如果操作不当,导致永久代内存溢出,也会抛出“OutOfMemoryError”异常。
永久代参数调整:
例如:-XX:MaxPermSize=10m 结果:
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10m; support was removed in 8.0
在JDK1.8之后就不存在永久代的设置了。元空间(JDK1.8以后):功能和永久代没太大区别。唯一的区别是永久代使用的堆内存而元空间是使用的物理内存。
元空间内存参数调整:
例如:-XX:MetaspaceSize=1m -XX:MaxMetaspaceSize=1m
Error occurred during initialization of VM
OutOfMemoryError: Metaspace
如果元空间内存太小也会“OOM”
四、堆内存参数调整(测试机器内存24G)
1、初始化内存和最大内存
public static void main(String[] args) { Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); System.out.println("maxMemory:" + maxMemory / 1024 / 1024 + "M"); System.out.println("totalMemory:" + totalMemory / 1024 / 1024 + "M"); } maxMemory:5452M totalMemory:368M
可以发现:默认情况下分配的内存是总内存的“1/4”,初始化内存大小是物理内存的“1/64”,也就是说可变内存是物理内存的“1/64 ~ 1/4”。
手动指定最大内存和初始化内存 -Xmx8G -Xms8G 再次输入结果为:
maxMemory:7851M totalMemory:7851M
这个时候就避免了伸缩区的可调策略,从而提高了程序的性能
2、观察GC的详细日志:-XX:+PrintGCDetails
控制台输出:
maxMemory:7851M totalMemory:7851M Heap PSYoungGen total 2446848K, used 167813K [0x0000000715580000, 0x00000007c0000000, 0x00000007c0000000) eden space 2097664K, 8% used [0x0000000715580000,0x000000071f961618,0x0000000795600000) from space 349184K, 0% used [0x00000007aab00000,0x00000007aab00000,0x00000007c0000000) to space 349184K, 0% used [0x0000000795600000,0x0000000795600000,0x00000007aab00000) ParOldGen total 5592576K, used 0K [0x00000005c0000000, 0x0000000715580000, 0x0000000715580000) object space 5592576K, 0% used [0x00000005c0000000,0x00000005c0000000,0x0000000715580000) Metaspace used 3532K, capacity 4498K, committed 4864K, reserved 1056768K class space used 387K, capacity 390K, committed 512K, reserved 1048576K
PSYoungGen:新生代 3/8
ParOldGen:老年代 5/8
默认情况下新生代和老年代内存大小比例为:3:53、内存可视化工具:
1、可视化工具:\jdk1.8.0_131\bin\jvisualvm.exe
1)、继续执行上步代码,将内存调整为最大内存调整为16G,方便查看过程。
-Xmx16g -Xms16g -XX:+PrintGCDetails
- 2)、运行程序,打开jvisualvm.exe找到当前执行的进程,打开监视,可以观察到CPU、堆等使用情况。
2、命令查看:jmap(jmap -heap PID)
1)、运行程序,Windows下打开cmd,输入taskList 找到 java.exe 观察其PID
C:\Users\Administrator>tasklist 映像名称 PID 会话名 会话# 内存使用 ========================= ======== ================ =========== ============ java.exe 10280 Console 1 5,241,504 K
2)、再输入 jmap -heap 10280 即可观察到内存使用情况
C:\Users\Administrator>jmap -heap 10280 Attaching to process ID 10280, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.131-b11 using thread-local object allocation. Parallel GC with 8 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 734003200 (700.0MB) NewSize = 134217728 (128.0MB) MaxNewSize = 244318208 (233.0MB) OldSize = 268435456 (256.0MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 100663296 (96.0MB) used = 18841312 (17.968475341796875MB) free = 81821984 (78.03152465820312MB) 18.717161814371746% used From Space: capacity = 16777216 (16.0MB) used = 6625856 (6.31890869140625MB) free = 10151360 (9.68109130859375MB) 39.49317932128906% used To Space: capacity = 16777216 (16.0MB) used = 0 (0.0MB) free = 16777216 (16.0MB) 0.0% used PS Old Generation capacity = 268435456 (256.0MB) used = 81936 (0.0781402587890625MB) free = 268353520 (255.92185974121094MB) 0.03052353858947754% used 5342 interned Strings occupying 461016 bytes.