1.虚拟机:(当前最广泛的是HotSpot虚拟机)
a.系统虚拟机(Vmware和Vitual Box)
b.程序虚拟机(阿里云等)
2.jvm主要组成:
3..堆、栈、方法区:
堆:解决数据存储的问题(如何存放.放在哪里) 自动化管理,通过垃圾回收机制,
垃圾对象会自动清理,不需要显示释放
新生代:新产生不久的对象
eden(伊甸园):刚new的对象存放到eden,被垃圾回收一次后进入s0或s1
s0(from):存放第一次垃圾回收后存活的对象(s0有对象时,s1则不能有)(gc完还存活,会直接将s0复制到s1,即复制算法)
s1(to):同理s0
大小s0==s1,并且可相互转换角色
老年代(tenured):存放产生比较久(垃圾回收多次)的对象
栈:解决程序的运行问题,(程序如何执行,数据如何处理)线程私有的内存空间:
局部变量表:用于报错函数的参数及局部变量
操作数栈:存储计算过程的中间结果,作为变量的临时存储空间
帧数据区(类似局部变量表):保存访问常量池的指针,存储函数返回或出现异常的异常处理表
方法区:辅助堆栈的一块永久区(Perm),解决堆栈信息的产生,类的数量和静态常量的数量过多,则会导致内存溢出(则需要增加方法区大小)
User user=new User() :User类的模版信息、静态信息都存在方法区中
user存在于栈中,user指向的实例存在于堆中
4.虚拟机参数:对系统调试和问题排查有帮助
-XX:对于系统级别(jvm)的配置,打印log级别等的信息、jvm使用什么样的垃圾回收器
非-XX:基本都是对应用层面上的配置
+:启用 -:禁用
-XX:+PrintGc:虚拟机启动后,只要遇到GC就会打印日志
-XX:+UseSerialGC 配置串行回收器
-XX:PrintGCDetails 可查看详细信息,包括各个区的情况
-Xms: 设置Java程序启动时初始堆大小
-Xmx: 设置Java程序能获得的最大堆大小
-Xms20m -Xmx20m -XX:+PrintCommandLineFlags(类似showversion):可将隐式或显示传给虚拟机的参数输出
-XX:+PrintCommandLineFlags可以让在程序运行前打印出用户手动设置或者JVM自动设置的XX选项,加上这个选项可以辅助问题诊断。
一般在工作中,会将初始堆的大小与最大堆大小设置相等,原因是可减少程序运行时的垃圾回收次数,从而提高性能
jdk1.8将perm改为Metaspace
5.参数配置
-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags
初始20M 最大20M 新生代1ms0/s1和eden区比例 GC时打印信息 串行回收器
-Xmn:一般设置较大的新生代(堆的1/4到1/3之间)减少老年代的大小,
XX:SurvivorRatio=2 设置eden和from/to的比例
-Xms20m -Xmx20m -XX:NewRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
-XX:NewRatio=2 老年代与新生代比例为2:1
经验:不同的堆分布情况,会对系统执行产生一定影响,实际配置中,应根据系统的特点做出合力的配置,
策略:1.尽可能将对象预留在新生代,减少老年代的GC次数(耗性能)
2.设置新生代的绝对大小(-Xmn)
3.设置新生代和老年代的比例: -XX:NewRatio=老年代/新生代
6.内存溢出(OOM)-XX:+HeapDumpOnOutOfMemrorError -XX:HeapDumpPath 可设置导出堆信息的存放路径
参考连接:http://blog.csdn.net/jia20003/article/details/50703944
推荐:virtual vm 或Jconsole
内存分析工具:MemoryAnalyzer1.5
eclipse下载地址:http://download.eclipse.org/mat/1.5/update-site/
jdk1.8配置临界值(低于25M就会报错):
-Xms25m -Xmx25m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=E:/testDir/error.dump
7.-Xss指定线程的最大栈空间,直接决定函数可调用的最大深度(常见递归,StackOverFolw)
方法区(永久区):是一块所有线程共享的内存区域,用于保存系统的类信息,默认值:-XX:MaxPermSize为64M
当系统的类相当多时,需要设置合适的方法区,以免出现永久区内存溢出,
-XX:PermSize=64M -XX:MaxPermSize=64M
8.目前Jvm支持Client和Server两种模式,1.7之后为Server模式
-client可指定使用Client模式 (不追求系统长时间使用性能仅仅是测试时推荐)
-server使用server模式(启动较慢,原因是会对其进行复杂的系统性能信息收集和使用更复杂的算法对程序进行优化)
一般生产环境都会Server模式(长期运行性能远快于Client模式) ,java -version即可查看何种模式
9.垃圾回收(GC):清理存于内存中、不会再被使用的对象
常见算法:引用计数法、标记压缩法、复制算法、分代、分区
10.引用计数法(经典):在对象被其他引用时计数器加1,当引用失败时减1,缺点:a.无法处理循环引用的情况(如递归等) b.进行加减操作比较浪费系统性能
标记清除法:分为标记和清除两个阶段进行处理内存中的对象,但是容易导致内存碎片问题,垃圾回收后的空间不连续,导致其工作效率低于连续的工作空间
复制算法:将内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中存留对象复制到未被使用的内存块中去,之后清除之前正在使用的内存块中所有的对象,反复交换两个内存的角色,完成回收。(新生代的from和to空间就使用此算法)
标记压缩法:基于标记清除法之上做的优化,把存活的对象压缩到内存的一端,再进行垃圾清理(老年代使用此算法)
分代算法:根据对象的特点把内存分成N块,根据每个内存的特点使用不同的算法。对于新生代回收频率高,耗时短和老年代回收频率低、耗时长的特点,赢尽量减少老年代的GC
分区算法:将整个内存分为N个小的独立空间,然后细粒度的控制单次回收部分小空间,而非对整个空间的GC, 从而提高性能,减少GC的停顿时间
11.垃圾回收时的停顿现象:垃圾回收器的任务是识别和回收垃圾对象进行内存清理,为了让垃圾回收器可以高效执行,大部分情况下,系统会进入一个停顿的状态(终止所有的应用线程,以避免不会有新的垃圾产生,同时确保系统状态在该瞬间下的一致性,也有利于更好的标记垃圾对象)
12.对象进入老年代的条件:一般对象首次创建会被放置在新生代的eden区,如果没有GC介入,则对象不会离开eden区;一般而言,只要对象的年龄(GC次数决定,新生代每次GC后没有被回收则年龄加1)达到一定的大小,就会自动进入老年代,-XX:MaxTenuringThreshold 控制新生代对象的最大年龄(即多少次GC后进入老年代),默认为15
此外,大对象(新生代eden区无法装入时,也会直接进入老年代),-XX:PretenureSizeThreshold 设置对象晋升为老年代的大小,但要注意TLAB区域优先分配空间
13.TLAB(Thread Local Allocation Buffer)区:线程本地分配缓存,线程专用的内存分配区域,为了加速对象分配而生。每个线程都会有一个独享的TLAB工作区域,Jvm通过TLAB区来避免多线程冲突问题,提高对象分配的效率。TLAB 一般不会太大,当对象无法在TLAB分配时,则会直接分配到堆上。
-XX:+UseTLAB 使用TLAB -XX:TLABSize 设置TLAB大小
-XX:TLABRefillWasterFraction 设置维护进入TLAB空间的单个对象大小(比例值,默认64,即如果对象大于整个空间的1/64,则在堆创建对象)
-XX:+PrintTLAB 打印TLAB信息
-XX:ResizeTLAB 自动调整TLABRefillWasterFraction阈值
-XX:-DoEscapeAnalysis -server 禁用掉,能打印TLAB(线程内核级别)信息
14.对象创建的基本流程:根据数据的大小,参数的设置,决定如何创建分配,以及分配的位置