一. java虚拟机
系统虚拟机和程序虚拟机,java虚拟机是一种程序虚拟机,jvm的基本结构有:类加载器,方法区,堆,直接内存,栈,本地方法栈,pc寄存器,垃圾收集系统,执行引擎。
类加载器:负责从文件和网络中加载class信息,加载的信息存放在方法区。
方法区:存放类信息,常量信息,常量池信息,包括字符串字面量,数字常量。
java堆:java虚拟机启动时,建立java堆,他是java内存的最主要工作区,几乎所有的实例对象都存放在java堆中,堆空间是所有线程共享的。
直接内存(堆外内存):Java的nio库允许java程序直接使用直接内存,从而提高性能,通常直接内存的速度优于java堆,读写频繁的情况下,考虑使用。主要用于存放对象,存取速度慢,可以运行时动态分配内存,生存期不需要提前确定。抛出java.lang.OutOfMemoryError。
栈:每个虚拟机线程都有一个私有的栈,一个线程的java栈在线程创建时被创建,java栈中保存局部变量,方法参数,Java方法的调用,返回值等。主要用来执行程序,存取速度快,大小和生存期必须确定,缺乏灵活性。抛出java.lang.StackOverFlowError。
本地方法栈:本地方法栈用于本地方法调用,java虚拟机允许java直接调用本地方法。
垃圾回收系统:
pc寄存器:是每个线程私有空间,java虚拟机会为每个线程创建pc寄存器,在任意时刻一个java线程总是在执行一个方法,这个方法成为当前方法,如果当前方法不是本地方法,PC寄存器会执行当前正在被执行的指令,如果是本地方法,pc寄存器值为undefined,寄存器存放当前执行环境指针,程序计数器,操作栈指针,计算的变量指针等信息。
虚拟机执行引擎:负责执行虚拟机的字节码。
二. 堆
几乎所有对象都存放在java堆中,通过垃圾回收机制自动化管理。新生代和老年代,新生代存放新生对象或年龄不大的对象,老年代存放老年对象。新生代分为eden区,s0区,s1区,(from区和to区两块大小相等,可以互换角色的空间)
年龄的判断由GC的次数来界定,对象首先放入eden区。
minnor GC的复制算法,from区和to区每次只使用一块,当垃圾回收时, eden区所有存活的对象都被移动到to区,from区年龄未达到阈值的对象也会被移动到to区,这样,eden区和to区都被清空了。这样,原来的from区变成了新的to区,原来的to区变成新的from区,这样循环,直到to区慢了,将所有对象移动到老年代。
二. 栈
java栈是一块线程私有的内存空间,一个栈有三个部分:局部变量表,操作数栈,帧数据区
局部变量表:局部变量和函数参数
操作数栈:保存计算的中间结果,临时变量。
帧数据区:保存常量池指针,异常处理表。
三. 方法区
存放类,final常量池,static静态区
四. 设置参数
-Xmx512m -Xms512m -Xmn256m -Xss1m -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
-Xmx512m:设置jvm最大可用内存为512m
-Xms512m:设置jvm初始内存为512m,此值可设置与-Xmx相同,以避免每次垃圾回收完成后重新分配jvm内存
-Xmn256m:设置年轻代为256m,整个堆大小=年轻代大小+老年代大小+持久代大小,持久代一般固定大小为64m,所以增大年轻代会减少老年代,官方推荐为整个堆的3/8
-Xss1m:设置每个线程的堆栈大小。
-XX:NewRatio=4:设置年轻代和老年代的比值,不含持久代。
-XX:SurvivorRatio=4:设置年轻代中eden和survivior区(一个)的比值,
-XX:MaxPermSize=16m:设置持久代大小为16m
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。
五. 垃圾回收算法
1. 引用计数法:对象被其他引用时计数器+1,引用失效时-1。无法处理循环引用,每次加减操作浪费系统性能(java没有用这种方法)
2. 标记清楚法:分为标记和清除两个阶段进行处理内存中的对象。会产生大量内存碎片(java现在也没用)
3. 复制算法:见上文(java堆新生代)
4. 标记压缩法:(老年代采用),标记压缩法由标记阶段和压缩阶段组成,先标记,然后把不需要清理的聚集到一端。因为老年代中的对象,很有可能大部分都存活,所以先将大部分存活的压缩在一端,只需清理一下块内存。为什么full gc慢,因为会移动对象的内存地址。
5. 分区算法:(1.7之后的新方法)将内存分为N个小独立空间,每个小空间独立使用。细颗粒度的控制gc而不在全部空间gc。
垃圾回收时,会产生停顿,stop the world