一. Java虚拟机内存模型
1. JVM内存数据分为程序计数器,虚拟机栈,本地方法栈,Java堆和方法区等部分;
2. 程序计数器
程序计数器是一块很小的内存空间,每一个线程都必须用一个独立的程序计数器,用于记录下一条要运行的指令,各个线程之间的计数器互不影响,独立工作,是一块线程私有的内存空间;如果当前线程正在执行一个Java方法,则程序计数器记录正在执行的Java字节码地址,如果当前线程正在执行一个Native方法,则程序计数器为空;
3. 虚拟机栈
Java虚拟机栈也是线程私有的内存空间,和Java线程在同一时间创建,保存方法的局部变量,部分结果,参与方法的调用和返回;
在Hot Spot虚拟机中,可以使用-Xss参数来设置栈的大小,栈的大小直接决定了函数调用的可达深度;
如果请求的栈深度大于最大可用的栈深度,则抛出StackOverflowError,如果在动态扩展栈的过程中,没有足够的内存空间来支持栈的扩展,则抛出OutOfMemoryError;
4. 本地方法栈
本地方法栈用于管理本地方法的调用;在SUN的Hot Spot虚拟机中,不区分本地方法栈和虚拟机栈;
5. Java堆
几乎所有的对象和数组都是在堆中分配空间的;
Java堆分为新生代和老年代两个部分,新生代用于存放刚刚产生的对象和年轻的对象,老年代用于存放存在时间较长,经过垃圾回收次数较多的对象;
新生代又可以细分为:
eden:伊甸园,即对象的出生地,存放刚刚建立的对象;
survivor space0:s0或者from space;存放其中的对象只是经历了一次垃圾回收,并得以幸存;
survivor space1:s1或者to space;
6. 方法区
方法区主要保存的信息是类的元数据,包括类的类型信息,常量池,域信息,方法信息;
在Hot Spot中,方法区也成为永久区,是一块独立于Java堆的内存空间;
二. 内存分配参数
1. 设置最大堆内存:-Xmx
2. 设置最小堆内存:-Xms,JVM会试图将系统内存尽可能限制在-Xms中,如果数值较小,会更加频繁的进行GC操作;
3. 设置新生代大小:-Xmn,一般设置为整个堆空间的1/4到1/3左右;
4. 设置持久代(方法区):-XX:MaxPermSize设置持久代的最大值,-XX:MaxPermSize设置持久代的初始大小;持久代的大小直接决定了系统可以支持多少类定义和多少常量;
5. 设置线程栈:-Xss;
6. 设置新生代中eden和s0空间的比例关系:-XX:SurvivorRatio;
7. 设置新生代和老年代的比例:-XX:NewRatio;
8. 设置堆空间最小空闲比例:-XX:MinHeapFreeRatio;
9. 设置堆空间最大空闲比例:-XX:MaxHeapFreeRatio;
10. 设置新生代大小:-XX:NewSize;
11. 设置survivor区的可使用率:-XX:TargetSurviorRatio,当空间使用率达到这个数值时,会将对象送入老年代;
三. 垃圾收集基础
1. 垃圾回收算法与思想
引用指数法:为每一个对象配备一个整型的计数器,用来记录被引用的次数;无法处理循环引用的情况;
标记-清除算法:从根节点,标记所有从根节点开始的可达对象,清除所有未被标记的对象;最大问题是空间碎片;
复制算法:将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收;在存活对象少,垃圾对象多的前提下效率高,缺点是将系统内存折半;在新生代串行垃圾回收器中,使用了复制算法的思想;
标记-压缩算法:标记后,将所有的存活对象压缩到内存的一端,之后清理边界外所有的空间;避免了碎片的产生,又不需要两块相同的内存空间;是一种老年代的回收算法;
增量算法:让垃圾收集线程和应用程序线程交替执行;减少系统的停顿时间,但因为线程切换和上下文转换的消耗,造成系统吞吐量的下降;
2. GC相关参数
与串行回收器相关的参数:
-XX:+UseSerialGC:在新生代和老年代使用串行收集器;
-XX:SurvivorRatio:设置eden区大小和survivor区大小的比例;
-XX:PretenureSizeThreshold:设置大对象直接进入老年代的阈值;
-XX:MaxTenuringThreshold:设置对象进入老年代的年龄的最大值;
与并行GC相关的参数:
-XX:+UseParNewGC:在新生代使用并行收集器;
-XX:+UseParallelOldGC:在老年代使用并行收集器;
-XX:ParallelGCThreads:设置用于垃圾回收的线程数;
-XX:MaxGCPauseMillis:设置最大垃圾收集停顿时间;
-XX:GCTimeRatio:设置吞吐量大小;
-XX:+UseAdaptiveSizePolicy:打开自适应GC策略;
与CMS回收器相关的参数:
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器;
-XX:ParallelCMSThreads:设定CMS的线程数量;
-XX:CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发;
-XX:+UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片的清理;
-XX:CMSFullGCsBeforeCompaction:设定进行多少次CMS垃圾回收后,进行一次内存压缩;
-XX:+CMSClassUnloadingEnabled:允许对类元数据进行回收;
-XX:+CMSParallelRemarkEnabled:启用并行重标记;
-XX:CMSInitiatingPermOccupancyFraction:当永久区占用率达到这一百分比时,启动CMS回收;
-XX:UseCMSInitiatingOccupancyOnly:只在到达阈值的时候才进行CMS回收;
-XX:+CMSIncrementalMode:使用增量模式,比较适合单CPU;
与G1回收器相关的参数:
-XX:+UseG1GC:使用G1回收器;
-XX:+UnlockExperimentalVMOptions:允许使用实验性参数;
-XX:MaxGCPauseMillis:设置最大垃圾收集停顿时间;
-XX:GCPauseIntervalMillis:设置停顿间隔时间;
四. 实用JVM参数
1. JIT编译参数
-XX:CompileThreshold:设置JIT编译的阈值,当函数的调用次数超过时,JIT就将字节码编译成本地机器码;
-XX:+CITime:打印JIT编译的耗时;
-XX:+PrintCompilation:打印JIT编译的信息;
2. 堆快照Dump
-XX:+HeapDumpOnOutOfMemoryError:在程序发生OOM时,导出应用程序的当前堆快照;
-XX:HeapDumpPath:指定堆快照的保存位置;
3. 错误处理
-XX:OnOutOfMemoryError:虚拟机在错误发生时运行的一段第三方脚本;
4. 取得GC信息
-XX:+PrintGC:简要的GC信息;
-XX:+PrintGCDetails:详细的GC信息;
-XX:+PrintGCTimeStamps:额外输出GC发生的时间;
-XX:+PrintTenuringDistribution:查看新生对象晋升老年代的实际阈值;
-XX:+PrintHeapAtGC:在GC时打印详细的堆信息;
-XX:+PrintGCApplicationStoppedTime:应用程序在GC发生时的停顿时间;
-XX:+PrintGCApplicationConcurrentTime:应用程序在GC停顿期间的执行时间;
-Xloggc:指定GC日志输出位置;
5. 类和对象跟踪
-XX:+TraceClassLoading:跟踪类加载情况;
-XX:+TraceClassUnloading:跟踪类卸载情况;
-XX:+PrintClassHistogram:打印运行时实例的信息;
6. 控制GC
-XX:+DisableExplicitGC:禁用显示的GC操作,即禁止在程序中使用System.gc()触发的Full GC;
-Xnoclassgc:在GC过程中,不会发生类的回收;
-Xincgc:增量式的GC;
7. 选择类校验器
-XX:-UseSplitVerifier:指定使用旧的类校验器;
-XX:-FailOverToOldVerifier:关闭再次校验的功能;
8. Solaris下线程控制
-XX:+UseBoundThreads:绑定所有用户线程到内核线程,减少线程进入饥饿状态的次数;
-XX:+UseLWPSynchronization:使用内核线程替换线程同步;
-XX:+UseVMInterruptibleIO:运行运行时中断线程;
9. 使用大页
-XX:+UseLargePages:启用大页;
-XX:LargePageSizeInBytes:指定大页的大小;
10. 压缩指针
-XX:+UseCompressedOops:在64位的虚拟机中打开指针压缩,一定程度上减少内存的消耗,但可能对性能造成一定的损失;