《深入理解Java虚拟机》 读书笔记

Java虚拟机运行时数据区

《深入理解Java虚拟机》 读书笔记

对象的创建

Java创建对象,在语言层面上使用new关键字。虚拟机遇到new关键字时,会检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,那就必须先执行类加载过程。类加载通过之后,虚拟机将会为新生对象分配内存。对象所需的内存在类加载完成后就能完全确定。分配内存的方法有“指针碰撞”和“空闲列表”两种方式,如果Java堆是规整的,则采用前者;否则,采用后者。Java堆是否规则和虚拟机有关。

深入理解Java虚拟机:JVM高级特性与最佳实践 第2版 高清PDF+源码 

OOM

在虚拟机中,能够发生OOM的有:虚拟机栈,本地方法栈,Java堆,方法区,运行时常量。分析OOM使用eclipse memory analyzer插件或者JProfiler工具。添加jvm参数(-XX:+PrintGCDetails)可以打印出GC的详细日志,-Xloggc:gc.log 日志文件的输出路径。

Java堆

几乎所有的对象的视力都在这里分配内存。通过参数-Xmx(JVM最大可用内存)和-Xms(JVM初始可用内存)控制对的大小。如果在堆中没有内存完成实例分配并且堆无法扩展,就会OOM。栈-Xss设置栈的容量大小。HotSpot不区分本地方法栈和虚拟机栈。如果虚拟机在申请栈扩展时,没有足够的空间,则会OOM。

垃圾收集器与内存分配策略

判断对象是否存活,两种方式:引用计数法和可达性分析。

引用计数法,不能解决对象相互引用的情况,所以主流虚拟机都采用的是可达性分析。

可达性分析采用采用GCROOTS策略,可作为GCROOTS的有:

虚拟机栈中引用的对象

方法区中类静态属性引用的对象

方法区中常量引用的对象

Native方法中引用的对象

一、不同虚拟机对比表

《深入理解Java虚拟机》 读书笔记

虚拟机新生代老年代垃圾算法备注
Serial         复制算法      
ParNew         复制算法      
Parallel Scavenge         复制算法      
Serial Old         标记-整理算法      
Parallel Old         标记-整理算法      
CMS         标记-清除算法      
G1         综合算法   目前最先进的垃圾回收器  
  二、理解GC日志

下面是一次GC产生的日志(jvm参数-XX:+PrintGCDetails):

《深入理解Java虚拟机》 读书笔记

从日志中可以看到,System.gc()表示程序调用了System.gc()方法触发了垃圾回收,[PSYoungGen:3932k->592k(76288k)]中PSYoungGen代表了GC发生的区域,这个名称和GC收集器密切相关:如果显示的是[DefNew,则表明是Serial收集器的新生代;如果是ParNew则表明是ParNew收集器的新生代;我们这里是PSYoungGen,则表明是Parallel Scavenge收集器的新生代。再看后面是数字,3932k->592k(76288k)代表的是:GC前该内存已经使用的容量->GC后该内存区域使用的容量(该内存区域总容量)。3932K->600K(251392K)表示GC前Java堆已经使用的容量->GC后Java堆已经使用的容量(Java堆总容量)。后面的时间表示GC所花费的时间,单位s。 

三、内存分配与回收策略 1、对象优先分配在Eden区

大多数情况下,对象首先会被分配到Eden区,当Eden区满了,会触发一次Minor GC。

大对象直接进入老年区

所谓的大对象是指,需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组(笔者列出的例子中的byte[]数组就是典型的大对象)。虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制(复习一下:新生代采用复制算法收集内存)。

2、长期存活的对象进入老年区

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/13822.html