-
内存快照如何抓取,怎么分析dump文件
-
类加载器的认识,rt-jar ext application
-
jvm的位置
- 运行在OS之上,和其他软件并行。java的东西运行在JVM
-
线程的话,java只能去利用底层的。
private native void start0();
-
沙箱安全机制
-
字节码校验器:检验类
-
Native
-
PC寄存器
-
方法区
-
栈和堆
-
三种jvm
-
新生区和老年区和永久区
-
堆内存调优
-
GC(Garbage Collection)
- 常用算法
-
jmm
JVM运行时数据区
-
method area:类,常量,常量池,静态变量,
-
heap(CG堆): 新生代,老生代。多个线程共享,可能划出线程的私有分区。没有内存将抛出OOM
-
私有:PC程序计数器。Java虚拟机栈。本地方法栈
-
线程结束,栈内存就释放了,对于栈来说,
不存在垃圾回收
-
栈内(栈帧):8大基本类型,对象引用,实例的方法
三种jvm:sun的hotspot
//native:说明java要调用底层。进入native method stack(内存区域),调用本地方法接口JNI
//本地方法栈是专门为了调用C/C++
堆分为
-XX:MaxTenuringThreshold=10
默认是15- 老年区:
- 永久区(元空间):非堆。存放jdk自身的class对象,存储的是一些运行环境或类信息,这个区域不存在垃圾回收。关闭jvm才回收。溢出:jar包,tomcat部署,反射类
CG垃圾回收:主要是在eden和老年区。99%都是临时对象
long l = Runtime.getRuntime().maxMemory();
long l1 = Runtime.getRuntime().totalMemory();
- 文件:idea64.exe.vmoptions也有信息。增大内存可以提高启动速度
- edit configurations:vm options
:-Xms1024m -Xmx1024m -XX:+PrintGCDetails
- X表示参数,memory size(默认1/64) ,memory max(默认1/4)。
OOM分析
-
安装插件jprofiler。下载软件jprofiler。配置jprofiler插件
路径/jprofiler.exe
-
对Test.java文件进行edit configuration……,JV options:
-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
-
运行Test.java(故意OOM),dump下文件进行分析
GC算法
- 重复算法:没有内存碎片,总有一个区是空的。适用:对象存活度低
- 标记清除法:两次扫描,有内存碎片
- 标记整理法:没有内存碎皮,多了移动成本
- 应用计数器法:
没有最好的算法,只有最合适的算法:GC --> 分代收集算法
- 新生区:重复算法
- 老年区:标记清除+标记整理 混合实现
基本
-
Hello.java
经javac编译成,字节码类文件Hello.class
,相邻之间没有缝隙,可以被JVM快速的加载至内存,并且占用较少的内存空间(利于网络传输),一次编译,多次使用
。每个类单独一个class文件 -
.class文件结构:
- magic字段:cafebase,判断是否是class文件
- version字段:
00 00
00 34
版本 - constant_pool
- 很多,等等
-
由于jvm运行在OS上,jvm屏蔽底层硬件,指令的,java可以实现跨平台。
-
JDK,JRE,JVM
-
学习JVM用于调优
深入学习
运行时数据区
-
class文件→JVM类加载器→JVM运行时数据区(需要
引擎
) -
JVM运行时数据区(Runtime data area)
- 方法区(非堆):类的信息,常量,静态变量。OutOfMemoryError
- 堆(Heap,GC堆):实例对象。OutOfMemoryError
- 新生代:eden,幸存区(from,to,总有一个空的)。eden满Minor GC。8:1:1。
- 老生代:Full GC。1:2
- 永久代=方法区
- 可能划分出多个线程私有的分配缓冲区
- PC:一个线程独有,记录执行的位置
- 虚拟机栈:单位是栈帧(局部变量,操作数栈,动态链接,出口)。局部变量:8大基本数据类型,对象引用地址。操作数栈:i=8*8,然后放入局部变量表。出口:return
- 本地方法栈:native(实现的方法在java中看不到),调用JNI(调用本地库)。本地方法栈就是C和C++代码
-
一个方法调用另一个方法,会创建新的栈帧。
-
栈指向堆:存储地址,指向堆的成员变量
JVM内存结构
- 直接内存:取决于真实的内存大小。分配慢,读写快
- 堆内存:分配快,读写慢
GC机制
-
在程序运行过程中,一些对象不用了(不可达,对于程序而言,它已经死了),需要垃圾回收
-
System.gc();重GC
只是建议
执行垃圾回收,但什么时候执行不可知 -
finalize方法:Object的方法(所有的类都继承了它),在GC之前调用finalize方法
-
GC算法:堆的分类此时就显得尤其重要,不同的类用不同GC算法
- 重复算法:新生区。浪费空间,节约时间
- 标记清除:还要扫描,有内存碎片。配合标记整理,用于老年区
- 标记整理:再浪费点时间整理一下碎片。
- 分代算法:就是上面三种
- 可达性
- 引用计数
垃圾收集器
- 垃圾收集器是GC算法的具体实现
- 新生代收集器:Serial,ParNew,Parallel Scavenage,
- 老生代收集器:CMS,Serial old(MSC),Parallel Old,
- 整堆收集器:G1,,,
JVM参数配置
- 内存参数
#常用的设置
-Xms:初始堆1/64
-Xmx:最大堆1/4
-Xmn:设置年轻代大小。堆=年轻代+年老代+持久代
-XX:NewSize=n 设置年轻代初始化大小大小
-XX:MaxNewSize=n 设置年轻代最大值
-XX:NewRatio=n 设置年轻代和年老代的比值。如: -XX:NewRatio=3,表示年轻代与年老代比值为 1:3,年轻代占整个年轻代+年老代和的 1/4
-XX:SurvivorRatio=n 年轻代中 Eden 区与两个 Survivor 区的比值。注意 Survivor 区有两个。8表示两个Survivor :eden=2:8 ,即一个Survivor占年轻代的1/10,默认就为8
-Xss:设置每个线程的堆栈大小。JDK5后每个线程 Java 栈大小为 1M,以前每个线程堆栈大小为 256K。
-XX:ThreadStackSize=n 线程堆栈大小
-XX:PermSize=n 设置持久代初始值
-XX:MaxPermSize=n 设置持久代大小
-XX:MaxTenuringThreshold=n 设置年轻带垃圾对象最大年龄。如果设置为 0 的话,则年轻代对象不经过 Survivor 区,直接进入年老代。
#下面是一些不常用的
-XX:LargePageSizeInBytes=n 设置堆内存的内存页大小
-XX:+UseFastAccessorMethods 优化原始类型的getter方法性能
-XX:+DisableExplicitGC 禁止在运行期显式地调用System.gc(),默认启用
-XX:+AggressiveOpts 是否启用JVM开发团队最新的调优成果。例如编译优化,偏向锁,并行年老代收集等,jdk6纸之后默认启动
-XX:+UseBiasedLocking 是否启用偏向锁,JDK6默认启用
-Xnoclassgc 是否禁用垃圾回收
-XX:+UseThreadPriorities 使用本地线程的优先级,默认启用
- GC收集器设置
-XX:+UseSerialGC:设置串行收集器,年轻带收集器
-XX:+UseParNewGC:设置年轻代为并行收集。可与 CMS 收集同时使用。JDK5.0 以上,JVM 会根据系统配置自行设置,所以无需再设置此值。
-XX:+UseParallelGC:设置并行收集器,目标是目标是达到可控制的吞吐量
-XX:+UseParallelOldGC:设置并行年老代收集器,JDK6.0 支持对年老代并行收集。
-XX:+UseConcMarkSweepGC:设置年老代并发收集器
-XX:+UseG1GC:设置 G1 收集器,JDK1.9默认垃圾收集器
类加载器
-
加载:将静态数据→方法区的运行时数据结构,并在堆中生成类,java类加载器(系统类加载器)由JVM提供
-
链接:把二进制合并到jre中,就是java二进制代码合并到jvm的运行状态之中
- 验证:符合规范,没有安全问题
- 准备:将类,static弄进方法区
- 解析:
-
初始化:执行类构造器
<clinit>
方法的过程 -
类加载器分类(4):
-
双亲委派机制:app→ext(jre\lib\ext)→boot(最终执行)。如果boot里面没有,再去ext,再去app
JVM可视化工具
- jdk1.8.0_05\bin\jvisualvm.exe监视
- jdk1.8.0_05\bin\jConsole.exe