1、堆内存(Heap)
说明:
used:represents the amount of memory currently used (in bytes)committed:represents the amount of memory (in bytes) that is guaranteed to be available for use by the Java virtual machinemax:represents the maximum amount of memory (in bytes) that can be used for memory management
2、元空间(metaspace)
说明:max、committed、used 说明同堆内存
3、代码缓存区(CodeCache)
说明:max、committed、used 说明同堆内存
4、JVM缓冲池(Buffer Pool)
说明:
direct(直接缓冲池):DirectByteBuffer的对象引用的内存块mapped(映射缓冲池):MappedByteBuffer的对象引用的内存块
5、JVM线程数
说明:
live(运行中的线程)deamon(守护线程)
6、GC
说明:
YGC:发生在新生代的垃圾回收FGC:发生在老年代的垃圾回收
7、JVM相关知识介绍
7.1 JVM内存模型(JVM规范)
方法区:
线程共享存储已被虚拟机加载的类信息、常量、类变量、即使编译器编译后的代码等数据
堆:
线程共享保存对象实例
虚拟机栈:
线程隔离描述方法执行执行的内存模型:每个方法执行时都会创建一个栈帧,每个栈帧存放的是局部变量表、操作数栈、动态链接、方法出口等信息,方法被调用到执行完成对应的是一个栈帧从入栈到出栈的过程如果线程请求的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟器栈动态扩展时没发申请到足够内存,会抛出OutOfMemoryError异常
本地方法栈:
线程隔离与虚拟机栈作用类似,只不过虚拟机栈执行的是java方法,本地方法栈执行的是native方法
程序计数器:
线程隔离可以看作是当前线程所执行字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成
7.2 Hotspot 实现的JVM内存模型
说明:
JDK8中虚拟机栈与本地方法栈已合并在JDK8之前,hotspot通过永久代(PermGen),实现JVM规范中的方法区,在JDK8中,增加了元数据区(metaspace)取代了永久代CodeCache中存放了JIT、JNI编译生成的native code
7.3 JVM垃圾回收(Garbage Collection)
7.3.1 如何标记对象不可用
- 引用计数法:给每个对象增加一个计数器,每当有一个地方引用它时,计数器加1,当失去引用时,计数器减1,当计数器为0时,判定对象不可用;
优点:简单高效;
缺点:无法解决对象循环引用的问题,可能导致内存溢出;
可达性分析法:以”GC Roots”作为对象起点,从此节点向下搜索,搜索所走过的路径成为引用链,当一个对象到GC Roots没有任何引用链时,则判定该对象不可用;
说明:GC Roots 为一组活跃的引用,比如当前正在被调用的方法的引用类型参数、局部变量等等
7.3.2 垃圾回收算法
- 标记–清理算法
算法思路:先标记出需要回收的对象,然后进行清理
优缺点:实现容易,因为要遍历所有对象,所以标记和清理两个过程效率都不高,特别是当对象数量较大的情况下,且容易产生碎片空间复制算法
算法思路:将可用内存等分为两块,每次只使用其中一块,当其中一块内存用完后,就将存活对象复制到另外一块内存,然后清理掉当前内存块
优缺点:适用于存活对象少的情况,算法执行效率高,但是可用内存只有原来的一半标记–整理算法
算法思路:标记过程同标记–清除算法,之后将存活对象移动到一端,然后直接清理掉边界以外的内存
优点:可以有效避免内存碎片的产生分代收集算法
算法思路:根据对象的存活周期,将内存划分为不同的块,每个块采用不同的回收算法
新生代:大部分对象的创建在Eden区,当Eden区满时,将存活的对象复制到Survivor1(from 区),并清空Eden,当S1区也满时,将Eden和S1中存活的对象复制到S2(to 区),并清空Eden和S1,以此往复,新生代的回收算法以复制算法为主;
老年代:经历过多次回收仍然存活的对象,会被放入老年代,因为老年代大部分的对象时存活的,所以使用标记–整理算法;
Minor GC/Young GC:发生在新生代的垃圾回收行为,因为java大部分的对象具有朝生夕灭的特性,所以新生代的垃圾回收非常频繁,一般回收速度也比较快;
Major GC/Full GC:发生在老年代的垃圾回行为,经常会伴随着至少一次的Minor GC,Major GC的回收速度比Minor GC慢数倍以上;
7.4 JVM缓冲池
JAVA NIO(JAVA Non-Blocking IO)
JDK1.4引入的用于IO操作的包,可替代标准的JAVA IO API。NIO与原来的IO有同样的作用和目的,只是使用方式完全不同。传统IO读写面向流(Stream,流是单向的),NIO读写面向缓冲区(buffer)和通道(channel,通道是双向的),可以更加高效的进行文件读取。在NIO中,所有的数据都是通过Buffer对象来处理的,程序不会将数据直接写入通道,而是写入由一个或多个字节组成的缓冲区,而当获取数据时,先将数据由通道读入缓冲区,再从缓冲区获取数据。
Buffer 继承树buffer本质上是一块可以读写的内存块,在JAVA中被包装成NIO Buffer对象,并提供了一组方法,用来访问该内存块。
DirectByteBuffer 和 MappedByteBuffer
DirectByteBuffer 和 MappedByteBuffer 对象引用的是堆外本地内存,叫作直接缓冲区,HeapByteBuffer对象引用的是堆内内存,也叫作非直接缓冲区;
I/O操作为啥要用直接缓冲?
先了解一下操作系统的I/O操作。操作系统的IO目标内存区域,必须是连续的字节序列,但JVM堆内字节数组无法保证连续(字节数组可能不会在内存中连续,而且由于GC机制,可能随时移动内存),所以JVM堆内字节数组不能直接用于IO操作。每次IO之前,必须将其复制到本机内存中,这样会导致明显的低效率,所以就引出了直接缓冲区,即直接与本机共享的内存区域
DirectByteBuffer:直接字节缓冲区,通过ByteBuffer.allocateDirect()方法创建
MappedByteBuffer:映射字节缓冲区,通过FileChannel.map()方法创建,用于将大文件或者使用较多的文件映射到内存中,以提高I/O效率



