一 运行时数据区
-XSS 调整栈内存
栈内存分配
1 保存参数,局部变量,中间计算过程和其他数据。退出方法的时候,修改栈顶指针就可以把栈帧中的内容销毁
2 栈的优点:存取速度比堆快,仅次于寄存器,栈数据可以共享
3 栈的缺点:存在栈中的数据大小,生存期是在编译时就确定的,导致其缺乏灵活性
决定了线程 的分配
假如 分配 20个 线程,那么 就要20M 内存
jvm堆配置参数 -Xms -Xmx
1 -Xms 初始堆大小
默认物理内存的1/64(<1GB)
2 -Xmx 最大堆大小
默认物理内存的1/4(<1GB),实际中建议不大于4GB
3 一般建议设置-Xms = -Xmx
好处是避免每次在gc后,调整堆的大小,减少系统内存分配开销
4 整个堆大小 = 年轻代大小 + 年老代大小 + 持久代大小
jvm 新生代 (young generation) -Xmn -XX:NewRatio -XX:SurvivorRatio -XX:NewSize , -XX:MaxNewSize
1 新生代 = 1个eden区 + 2个survivor区
2 -Xmn 年轻代大小(1.4版本之后 or lator)
-XX:NewSize , -XX:MaxNewSize(设置年轻代大小(for 1.3/1.4) )
3 -XX:NewRatio
年轻代(包括Eden和两个Survivor)区与年老代得比值(除去持久代)
Xms = Xmx并且 设置了 Xmn 的情况下,该参数不需要进行设置
4 -XX:SurvivorRatio
Eden区与Survivor区的大小比值,设置为8,则两个Survivor区与
一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
jvm 老年代 -XX:PretenureSizeThreshold=1024
1 年轻代中经过垃圾回收没有回收掉的对象 被复制代 老年代
2 老年代存储对象比年轻代 年龄大的多,而且不乏大对象
3 新建的对象也有可能直接进入老年代
大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024
(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是
直接在老年代分配,这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存拷贝.PretenureSizeThreshold 参数只对serial和ParNew两款收集器有效
下面 验证 PretenureSizeThreshold 参数 在 不同 垃圾收集器组合 上的 堆内存分配情况 使用的是jdk 1.8
package cn.shendu;
public class JvmDemo {
private static final int _1MB = 1024*1024;
public static void main(String[] args) {
byte[] allocation1,allocation2,allocation3,allocation4;
allocation1 = new byte[4 * _1MB];
}
}
这里使用了 Parallel Scavenge + Parallel Old 的收集器 组合 , 从GC日志 看出,并不会 进入 老年代
-XX:PretenureSizeThreshold=3145728 -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:+UseParallelOldGC
Heap
PSYoungGen total 9216K, used 5571K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 68% used [0x00000000ff600000,0x00000000ffb70fd8,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
ParOldGen total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000)
Metaspace used 2874K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 308K, capacity 386K, committed 512K, reserved 1048576K
这里使用了 ParNew + Serial Old的收集器组合,可以看出 他直接 进入了老年代
-XX:PretenureSizeThreshold=3145728 -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:+UseParNewGC 有效果
Heap
par new generation total 9216K, used 1475K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 18% used [0x00000000fec00000, 0x00000000fed70fc8, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 4096K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 40% used [0x00000000ff600000, 0x00000000ffa00010, 0x00000000ffa00200, 0x0000000100000000)
Metaspace used 2874K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 308K, capacity 386K, committed 512K, reserved 1048576K
-XX:MaxTenuringThreshold
虚拟机给每个对象定义了一个 年龄计数器。每经历一次young gc,s区里的对象没有被回收,年龄就增加1岁大对象复制到 S区,装不下,就会直接进入老年代。
元数据区
jdk1.8后,元数据区取代了永久代,跟永久代一样,元数据区是方法区的实现,是存放虚拟机加载类信息,静态变量,常量数据等, 在现有的软件开发项目中,CGLIB 和 javassist等动态字节码生成工具已经得到了非常普遍的使用。当系统中需要生成大量动态类时,对持久代的压力显然会比较大。
-XX:MetaspaceSize 元数据区初始化大小
-XX:MaxMetaspaceSize 元数据区最大大小
-XX:MinMetaspaceFreeRatio=40 如果空闲比小于这个参数,那么虚拟机将增长元数据区空间,40是百分之40的意思
-XX:MaxMetasaceFreeRatio=70 如果空闲比大于这个参数,那么虚拟机会释放元数据区的空间 ,70是百分之70的意思
二 垃圾回收器
parallel scavenge
开启 并行收集器 组合 -XX:+UseParallelGC Parallel Scavenge + Parallel Old
收集器也经常被称为 "吞吐量优先" 收集器。
parallel scavenge 收集器提供了两个参数用于精确控制吞吐量,
分别是控制最大垃圾收集停顿时间的 -XX:MaxGCPauseMillis参数
及直接设置吞吐量大小的-XX:GCTimeRatio参数,
-XX:UseAdaptiveSizePolicy,这是一个开关参数,当这个参数打开之后,虚拟机
会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量,这种调节方式称为
GC自适应的调节策略
Parallel Old收集器
开启 并行收集器 组合 -XX:+UseParallelGC Parallel Scavenge + Parallel Old
Parallel Old是 Parallel Scavenge收集器的老年代版本,使用多线程和"标记-整理"算法。在注重吞吐量及CPU
资源敏感的场合,都可以优先考虑Parallel Scavenge加入Parallel Old收集器
CMS 收集器
启动参数 UseConcMarkSweepGC,打开此开关后,使用ParNew+CMS+Serial Old 的收集器组合 进行内存回收,Serial Old收集器将作为CMS收集器 回收失败时 的 后备使用
CMS 收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的java应用都集中在互联网或B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求
-XX:CMSSInitiatingOccupancyFraction 设置CMS 收集器在老年代空间被使用多少后触发垃圾收集。默认值为68%,仅在使用CMS
收集器时生效
-XX:UseCMSCompactAtFullCollection 设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理。仅在使用CMS收集器时
生效
-XX:CMSFullGCsBeforeCompaction 设置CMS收集器在进行若干次垃圾收集后再启动一次内存碎片整理。仅在使用CMS收集器时
G1 收集器
开启G1收集器 -XX:+UseG1GC
G1 也是关注最小时延的垃圾回收器,也同样适合大尺寸堆内存的垃圾收集,采用的是复制整理算法。当CMS 效果不好时,可以考虑该垃圾回收器
具体 请参考 https://blog.csdn.net/coderlius/article/details/79272773
参考资料
深入理解java虚拟机
java程序性能优化指南