书籍:周志明的《深入理解java虚拟机-第二版》
JVM内存包括以下部分:
程序计数器,每个java线程一个,容量很小。会记录下一条字节码的地址。
java虚拟机栈,每个线程一个。每个方法执行的时候,创建一个栈帧Stack Frame.会存储java的基本数据类型以及reference引用。栈的层数过多是会抛出StackOverFlowError,内存不足,抛出OutOfMemeryError.
本地方法栈,为虚拟机使用到的Native方法服务,HotSpot的现实,将虚拟机栈和本地方法栈在一个空间里。同样会抛出上述的Error。
java堆,分为年轻代和年老代,Young和Eden, 年轻代通常有2个同等大小的区域,From Survivor, To Survivor交替承担内存分配责任。 Eden代回收称为FULL GC. 内存不够抛出OutOfMemeryError。
方法区,HotSpot的方法区称为永久代,MaxPermSize为启动配置上限。存放Class的信息和字节码等等,卸载一个类有严格的条件,HotSpot永久代的回收也是GC工作的一个部分。运行时常量池,是方法区的一部分。
直接内存区域,Java NIO中使用,DirectByteBuffer,可以避免java对象直接拷贝数据,netty等等异步通讯库的Zero Copy,依靠这个来实现。
java对象的内存结构:
java对象可以通过句柄或则指针直接访问。
垃圾回收:
对象存活算法:引用计数法, 对象可达性分析算法。Java使用后者。
引用类型有4种,
1 普通强引用:只有不可达的时候,才会被回收。
2 SoftReference:对象不可达,或则内存不够了,会被回收。
3 WeakReference:对象在下一次垃圾回收被回收了。
4 PhantomReference:无法引用到对象,幽灵引用,只可以实现一个垃圾回收的时候的消息监听。
finalize() 方法会在, gc第一次回收的时候调用, 如果第二次调用时候,则不会调用这个方法,平时别管他。
方法区的回收要满足下面三个条件:
垃圾回收算法,常见3个:
1 标记清除。 2 复制。 3 标记整理(专门针对年老代)4 分代收集算法(老对象和过大的对象直接进入年老代)
jvm有安全点的概念:
所有的线程都跑到安全点的时候, SafePoint, 都停下来,gc工作。
垃圾回收器:(默认的情况,会根据机器的内存大小和cpu决定使用server端或则client的何种收集器,自动选择)
1 Serial和 Serial Old收集器,是client模式下的默认回收器,单线程回收。
2.ParNew 是Serial的并行版本,也是要 一直Stop the World.
3 Parallel Scavenge和Parallel Old收集器,吞吐量优先收集器,可以设置 最大停顿的时间等等参数。
4 CMS 当前最好的 server 收集器,Concurrent Mark Swap, 分为4个阶段: 初始标记,并发标记,重新标记,并发清除。2和4阶段,应用线程可以并行执行。 有很多参数可以设置:比如触发的Eden内存百分比(默认68%),是否做内存碎片整理等等。 CMS并发清理会有浮动垃圾,但触发CMS的百分比过高的时候,造成CMS失败的时候,将启动后备的Serial Old 的收集器。
5 G1 还不成熟,以后可以研究。
常用参数:
-Xms 设置 Java 堆的初始化大小
-Xmx 设置最大的 Java 堆大小
-Xss 设置Java线程堆栈大小
-XX:+UseParallelGC 使用并行垃圾收集
-XX:-UseConcMarkSweepGC 使用并发标志扫描收集 (Introduced in 1.4.1)
-XX:-UseSerialGC 使用串行垃圾收集 (Introduced in 5.0.)
JVM调试参数,用于远程调试
-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
关于性能诊断的 JVM 参数
-Xprof
-Xrunhprof
-XX:PermSize and MaxPermSize