Java的内存总结
1. 内存分配的基本规则
①.对象优先在新生代Eden分配,当Eden不够时,将进行一次MinorGC
②.大对象之间进入老年代,比如像很长的字符串,数组等
③.长期存活的对象将进入老年代,每经过一次MinorGC就增加一岁,(默认是15),可以用参数进行调整(-XX:MaxTenuringThreshold=10)
④.并不是必须达到MaxTenuringThreshold才能晋升到老年代,如果在Survivor空间中相同年龄所有对象大小总和大于Survivor空间的一半,则年龄大于或者等于该年龄的对象直接进入老年代
2. java的内存参数配置汇总
JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小
-client
指示VM把应用当成客户端类程序进行优化,开启该参数时,对于这类程序而言,内存占用是最重要的性能标准,远比高吞吐量重要。
-server
指示VM把应用当成服务器类程序进行优化,该选项适用于高吞吐量比启动时间和内存占用更重要的应用程序。
(1)Java堆的初始值、最小值和最大值(新生代和老年代的总和)
-Xms<n>[g|m|k]
-Xmx<n>[g|m|k]
注:如果-Xmx大于-Xms,java的堆大小会依据应用的需求而扩展或缩减。堆的扩展和缩减需要FullGC,所以注重延迟和吞吐量性能的应用,应该吧这两个值设置成一样。
(2)设置方法区(永久代)初始值、最小值和最大值
-XX:PermSize
-XX:MaxPermSize
注:如果-XX:MaxPermSize大于-XX:PermSize ,永久代大小会依据应用的需要而扩展或缩减,尤其是在需要家长类或存储intern String时。永久代的扩展和缩减需要FullGC,所以注重延迟和吞吐量性能的应用,应该把这两个值设置成一样。
(3)新生代的初始值、最小值和最大值
-XX:NewSize=<n>[g|m|k]
-XX:MaxNewSize=<n>[g|m|k]
注:如果-XX:MaxNewSize大于-XX:NewSize ,新生代大小会依据应用的需要而扩展或缩减。新生代的扩展和缩减需要FullGC,所以注重延迟和吞吐量性能的应用,应该把这两个值设置成一样。
(4)同时设置新生代的初始值、最小和最大值(等同于上面两个参数设为一样)
-Xmn<n>[g|m|k]
(5)设置年老代与年轻代的比值
-XX:NewRatio
注:新生代和老年代的尺寸比,例如n为3,则比率为1:3.如果-Xms和-Xmx不同,且希望新生代和老年代的比率为恒定时,则这个命令比较有用。
(6)设置年轻代的Eden区与Survivor区的大小比值
-XX:SurvivorRatio
注:新生代的单个Survivor区于Eden区的大小的比率
(7)开启压缩指针特性
-XX:+UseCompressedOops
注:jdk6Update23之后默认开启,java引用从32位变为64位时带来了性能的损失,他是将64位的指针转换为相对于java堆基地址的32位偏移量。当java的-Xmx的值小于32G时可以开启此选项,提高性能,不够上限大约为26GB的时候性能最好。
(8)设置每个线程的栈大小
-Xss<n>[g|m|k]
注:DK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
(9)其他配置
①.收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
②.垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
③.并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
④.并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。
3. 如何提高性能(从内存方面)
①.尽早释放无用的对象引用(使用临时变量的时候,让引用变量在退出活动域后,设置为null,提高GC回收效率)
②.字符串(尽量使用String str = “hello”;避免使用String str = new String(“hello”);大量使用字符串操作时,尽量避免使用String,要是用StringBuffer/StringBuilder)
③.静态变量(尽量少使用静态变量,因为静态变量是全局的,GC不会回收)
④.尽量避免在类的构造函数里创建、初始化大量的对象(防止在调用其自身类的构造器时造成不必要的内存资源浪费,尤其是大对象,JVM会突然需要大量内存,这时必然会触发GC优化系统内存环境)
⑤.大集合对象(可以考虑分块进行处理,处理一块释放一块)
⑥.不要经常在调用方法中创建对象(尤其是忌讳在循环中创建对象,可以适当的使用hashtable创建一组对象容器,然后从容器中去取那些对象,而不是每次new之后又丢弃)
⑦.尽量不用finalize函数(垃圾回收器要回收对象的时候,首先要调用这个类的finalize方法;finealize()会加大GC的工作量,而GC相当耗费系统的计算能力;并且你也不知道finalize方法何时会被调用,是否被调用等)
⑧.分散对象的创建或删除时间
⑨.能用基本类型就不用包装类型(基本类型变量的占用内存资源比包装类型少的多)
⑩.尽量减少临时对象的使用(临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,减少了GC的机会)
⑪.避免使用System.gc()
4. JVM中最大堆大小有三方面限制:
①.操作系统的数据模型(32-bt还是64-bt)限制;32位系统一般限制在1.5G~2G;64位操作系统对内存无限制。
②.系统可用的虚拟内存限制
③.系统可用的物理内存限制
5. 参数使用的5种形式:
①.-XX:+<option> 开启option参数
②.-XX:-<option> 关闭option参数
③.-XX:<option>=<value> 将option参数设置为value
④.-<option> 直接启用参数
⑤.-<option><value> 直接设置option的值为value
6. JVM的典型配置
java -Xmx5120m –Xms5120m -Xmn2g -Xss128k
注:-Xmx5120m:设置JVM最大可用内存为5120M。
-Xms5120m:设置JVM初始内存为5120m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代大小为2G。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss128k:设置每个线程的栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
java -Xmx3550m -Xms3550m -Xss128k
-XX:NewRatio=4
-XX:SurvivorRatio=4
-XX:MaxPermSize=16m
-XX:MaxTenuringThreshold=0
注:-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代大小为16m。
-XX:MaxTenuringThreshold=0:设置年轻代最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收