内存管理
内存模型
- 堆和元空间为线程共享的内存区域。堆是用来存放对象的,包括new出来的对象和通过反射生成的对象,但对象并不是一定会放在堆上,要考虑逃逸分析和标量替换导致的栈上分配,这是JVM对内存管理的优化手段;元空间用来放常量池、类信息和类的静态变量,在jdk1.8之前叫永久代。
- 虚拟机栈、本地方法栈及程序计数器为线程独享的内存区域。虚拟机栈可以理解为线程栈,用于存放每个线程的局部变量表、操作数栈、动态链接、方法出口;本地方法栈主要放native的方法;程序计数器可以理解为线程执行到哪里了,在CPU调度和GC时,线程可能会暂停,当线程获得CPU时,可以通过程序计数器知道该从哪里往下执行。
内存分配
指针碰撞
默认使用的是指针碰撞。
如果Java堆中的内存是绝对规整的,所用用过的内存放在一边,没有用过的放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存仅仅是把指针往空闲空间那边挪一段与对象大小相等的距离。
空闲列表
如果Java堆中的内存并不是规整的,已使用的和空闲的内存相互交错,那就没办法简单的进行指针碰撞,虚拟机需要维护一个列表,记录哪些内存块是可用的,在分配的时候找到一个足够大的块分配给对象,并更新列表上的记录。
解决内存分配并发问题
- CAS
- 本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)
垃圾回收
分代收集理论
堆内存被分为年轻代和老年代,年轻代又分为eden区和survivor区。
正常情况对象在堆上分配空间时,会放入年轻代的eden区(大对象另说),当eden区空间不足会发生Allocation Failure,导致minor gc,存活的对象进入survivor区;survivor区的对象到达一定年龄后被挪到老年代,当老年代空间不足,或者满足了老年代空间担保机制,老年代触发full gc。
垃圾收集算法
- 标记-复制算法
- 标记-清除算法
- 标记-整理算法
垃圾收集器
- Serail收集器
单线程垃圾收集器,收集效率高,但是会阻塞用户线程。 - Parallel收集器
多线程垃圾收集器。 - ParNew收集器
并发垃圾收集器,可以与用户线程并行执行。 - CMS收集器
只能在老年代使用,主流的垃圾收集器为ParNew+CMS。 - G1收集器
内存相当大的时候可以使用G1垃圾收集器。 - ZGC收集器