参考资料:
《深入理解 Java 虚拟机 - JVM 高级特性与最佳实践》
第1部分主题为自动内存管理,以此延伸出 Java 内存区域与内存溢出、垃圾收集器与内存分配策略、参数配置与性能调优等相关内容;
第2部分主题为虚拟机执行子系统,以此延伸出 class 类文件结构、虚拟机类加载机制、虚拟机字节码执行引擎等相关内容;
第3部分主题为程序编译与代码优化,以此延伸出程序前后端编译优化、前端易用性优化、后端性能优化等相关内容;
第4部分主题为高效并发,以此延伸出 Java 内存模型、线程与协程、线程安全与锁优化等相关内容;
本系列学习笔记可看做《深入理解 Java 虚拟机 - JVM 高级特性与最佳实践》书籍的缩减版与总结版,想要了解细节请见纸质版书籍;

类信息、常量、静态变量,即时编译器编译后的代码等数据。当方法区无法满足内存分配需求时,抛出 OutOfMemoryError 异常;对象实例和数组。是垃圾收集器管理的主要区域。可能划分出多个线程私有的分配缓冲区。目的是为了更好的回收内存,或者更快的分配内存。可以处于物理上不连续的内存空间中。没有内存可以完成实例分配,并且堆也无法再扩展时,将会抛出 OutOfMemoryError 异常;虚拟机字节码指令的地址,否则 Undefined。Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的。每条线程都有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储。是虚拟机中唯一没有规定 OutOfMemoryError 情况的区域;栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息;方法参数和方法内定义的局部变量。存放编译期可知的各种基本类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,能找到对象在 Java 堆中的数据存放的起始地址索引,与对象所属数据类型在方法区中存储的类型信息)、returnAddress类型(指向了一条字节码指令的地址)。线程安全。通过索引定位方式使用局部变量表,容量以变量槽(slot)为最小单位;

耗费高性能,堆内存申请空间耗费比较低;IO 读写的性能优于堆内存,在多次读写操作的情况相差非常明显;

垃圾回收机制的缺点:是否执行,什么时候执行却是不可知的;
类静态属于引用的对象;常量引用的对象;System.gc()Object.finalize()废弃的常量(没有该常量的引用)和无用的类(所有实例已回收、该类的 ClassLoader 已回收、无法通过反射访问);“标记-清理”算法或者“标记-整理”算法。大对象、长期存活对象分配在老年代;复制算法有关);老年代可用连续空间大小 < 新生代对象总大小 时,查看相关参数判断是否允许担保失败。允许则判断是否:年代可用连续空间大小 > 历次晋升老年代对象平均大小,成立则进行 Major GC(有风险);不成立说明老年代可用连续空间很少,进行 Full GC。或者不允许担保失败也会进行 Full GC;老年代可用连续空间大小 > 新生代对象总大小 或 老年代可用连续空间大小 > 次晋升老年代对象平均大小 时,进行 Major GC。反之进行 Full GC;垃圾回收算法是内存回收的理论,垃圾回收器是内存回收的实践;

最短回收停顿时间为目标的收集器,适用于互联网站或者 B/S 系统的服务端上。并发收集、低停顿。与用户线程可以同时工作;调优目的:GC 的时间足够的小、GC 的次数足够的少、发生 Full GC 的周期足够的长;
问题原因:Full GC 的停止用户线程的 STW 时间过长,应尽量避免;
Full GC 触发条件:主要是两个:老年代内存过小、老年代连续内存过小;
控制 Full GC 频率的关键:保障老年代空间的稳定,大多数对象的生存时间不应当太长,尤其是不能有成批量的、长生存时间的大对象产生;
-XX:+HeapDumpOnOutOfMemoryError 参数 -> 运行一段时间发现存在大量 t.NAKACK 对象;-XX:MaxDirectMemorySize 调整直接内存大小;-Xss 调整线程堆大小;Runtime.getRuntime().exec() 方法创建大量进程;HashMap<Long,Long> 类型 key 和 value 共占 2*8=16 字节,封装成 Map.Entry 后多了 16 字节对象头、8 字节 next 字段和 4 字节 int 类型的 hash 字段,为了对其追加 4 字节空白对象头,还有 8 字节对这个 Map.Entry 的引用。最后实际耗费的内存为 (Long(24byte)×2)+Entry(32byte)+HashMap Ref(8byte) = 88byte,空间效率为:16 字节 / 88 字节 = 18% 太低;-XX:SurvivorRatio=65536、-XX:MaxTenuringThreshold=0;-XX:+Always-Tenure;-Dsun.awt.keepWorkingSetOnMinimize=true;-XX:+PrintGCApplicationStoppedTime-XX:+PrintGCDate-Stamps-Xloggc:gclog.log -> 确认了停顿确实是由垃圾收集导致;-XX:+PrintReferenceGC 参数,找到长时间停顿的具体日志信息 -> 发现从准备开始收集,到真正开始收集之间所消耗的时间却占了绝大部分;-XX:+PrintSafepointStatistics 和 -XX:PrintSafepointStatisticsCount=1 查看安全点日志 -> 发现虚拟机在等待所有用户线程进入安全点时有线程很慢;-XX: +SafepointTimeout 和 -XX:SafepointTimeoutDelay=2000 两个参数,使虚拟机在等到线程进入安全点的时间超过 2000 毫秒时就认定为超时 -> 输出导致问题的线程名称;