JVM内存及GC回收

JVM体系结构概述

1)、简述

JVM——操作系统——硬件体系
PS:安卓(jvm+linux内核)
Classfile——类装载子系统(入口)——运行时数据区——执行引擎(出口)——本地方法接口——本地方法库

2)、三种JVM(java规范)

①Sun公司的HotSpot(被Oracle收购)
②BEA公司的JRockit(被Oracle收购)
③IBM公司的J9 VM

运行时数据区

JVM内存及GC回收_第1张图片

1)、方法区

是堆的一个逻辑部分,但其还有个别名(Non-Heap)
所有线程共享
存储已经被虚拟机加载的类信息、常量、静态变量、运行时常量池
即编译器编译后产生的数据等
JVM虚拟机停下来进行回收

2)、Java栈

存储局部变量+实例方法,局部变量表存放了编译器可知长度的各种基本类型、对象引用(堆中地址)
方法执行完,自动释放,不存在垃圾回收问题
栈帧:本地变量、栈操作、栈帧数据

3)、本地方法栈

本地方法接口、本地方法库(ddl)
Native Method Stack登记native方法,在Execution Engine执行时加载本地方法库
启动线程和进程时,由操作系统控制

4)、Heap堆

一个JVM只存在一个堆内存,其大小可以调节。类加载器读取类文件后,需要把类方法、常变量存放到堆内存中,保存所有引用类型的真实信息,方便执行器执行

逻辑上三部分(Java7之前)
新生区(Young/New)、养老区(Old/Tenure)、永久区(Perm)
JVM内存及GC回收_第2张图片
①新生区分为:
Eden(伊甸区,大小占比:8)、 Survivor 0(1)、Survivor 1(1)(from/to区)

Eden区满了经历MinorGC,幸存者存储到Survivor 0,再满将Eden和S0有效存储到S1,S0和Eden进行清空;再满将Eden和S1有效存储到S0,S1和Eden进行清空,默认反复15次
Ps:当Eden区的幸存者过多时,会直接进入养老区

②进入养老区(链接池、线程池等)
养老区满时,触发FullGC,清理不了会报java.lang.OutOfMemoryError

③永久区(和新生区及养老区无直接关联)
常驻内存区域,存放JDK自身携带的Class、Interface等,运行环境必需信息
不会被垃圾回收回收掉

堆结构在jdk版本迭代下的变化
Jdk1.6及之前:有永久代,常量池在方法区
Jdk1.7:有永久代,已逐步“去永久代”,常量池在堆
Jdk1.8及以后:无永久代,常量池在元空间(方法区)
JVM内存及GC回收_第3张图片

5)、程序计数器(PC寄存器)

每个线程都私有一个程序计数器(指针),指向方法区中的方法字节码(用来存储
指向下一条指令的地址),由执行引擎读取下一条指令,是一个非常小的内存空间,自动释放

6)、JVM参数调优

①默认为:内存/64~~~~~内存/4
查看内存:Runtime.getRuntime().maxMemory()/totalMemory()
JVM内存及GC回收_第4张图片
②调节并打印内存:-Xms大小 -Xmx大小 -XX:+PrintGCDetails
JVM内存及GC回收_第5张图片
Tips:MAT插件(Eclipse插件)可分析dump文件,定位内存泄漏
使用-Xms大小 -Xmx大小 -XX:+HeapDumpOnOutOfMemoryError 来产生dump文件
使用IDEA时,需设置dump文件位置 -XX:HeapDumpPath=路径



GC回收(分代收集算法)

1)、引用计数法(被淘汰)

需维护计数器,较难处理循环引用

2)、复制算法(Copying)

年轻代Minor GC使用,默认15次,可通过-XX:MaxTenuringThreshold来设定
效率高、无内存碎片,需要双倍空间(需存活率较低)

3)、标记清除(Mark-Sweep)

老年代FullGC,标记(对存活对象标记),清除(扫描,回收未标记对象)
不需要额外空间、但需扫描两次,产生内存碎片
Ps:执行标记清除时,需暂时停止功能(避免刚进入恰好标记完,未被标记的对象清除)

4)、标记压缩(Mark-Compact)

老年代FullGC,标记(对存活对象标记),压缩(将存活对象转移到连续内存)
效率不高,需暂时停止功能

5)、标记清除压缩(Mark-Sweep-Compact)

结合Mark-Sweep和Mark-Compact

你可能感兴趣的:(JavaEE,jvm,jdk)