About JVM Tuning

Turn  https://www.java123.vip/wp/

NOTE: JVM7 below shows the structure of the memory, JVM8 perm space in the following modifications: Java7 → Java8 Permanent → Metaspace the following discussion will be based on the physical memory of the memory structure deployed JVM7.

 JVM for the Java Runtime Environment, which is the data Java program is run by the JVM to manage, how to manage these data is our daily said the JVM tuning.

JVM storage area can be divided as follows (listed only area we want to analyze your own access to information in other regions)

 We look at the following code

 

I expressed the above code in memory storage case with color. I.e. a local variable on the stack region; new new objects present in the heap area; class definition file is present in the process region;

 Stack area

Characteristics of the stack area is fast, the local variables are present in this region, directly by the CPU at the time of execution of the instruction operation.
Using a stack push way to allocate and free up space, met a left parenthesis variable into the stack, the stack variable encounter a right parenthesis.
After the stack because the variables, this region was released, so the local variables will not be used outside of the closing parenthesis. This also explains the scope of variables.

We see StackOverFlow anomaly is this area is full, because the encounter right parenthesis will free up space, so this area is rarely as simple a method of multi-variable cause this exception.
Usually because the recursive method call hierarchy too deep, causing all of the local variables are not released, was followed by StackOverFlow exception.
We can set -Xss to develop the size of this space parameters.

 Heap

Java programs in the heap memory allocated a space to store the object data through new command, but did not programmable instructions to delete this data, that is, when we write programs just new object. If there is no procedure to remove the object, then the heap will soon run out of memory, reported OutOfMemoryException: heap space.

既然Java语言让我们省去了以编程的方式来管理内存可能带来的某些内存未被释放的危险,那么Java在运行时就要提供一套对不再使用的内存空间回收的方法。
我们称这个为Java的垃圾回收机制。
JVM的垃圾回收由垃圾回收器完成,可以制定不同的垃圾回收器来按不同的规则进行垃圾回收,我们可以根据需要指定最适合我们的垃圾回收器。
我们可以通过-XX参数来指定垃圾回收器。

本文中我们介绍常用分代回收算法。
把开始的图再贴一下:

Heap(堆内存)=eden+2survivor(年轻代)+ParOldGen(老生代)+Perm(jdk8以前)。jdk8以后将永久代替换为MetaSpace(元空间)存在于本地内存。from survivor 和 to survivor大小相同,且保证一个为empty。

 Heap Memory就是我们说的堆内存,存储对象,我们首先把讨论范围限定在这块区域。

一个对象从创建到消亡的过程如下:
1. 我们用new关键字创建的对象,首先出生在伊甸园,即图中的绿色部分(eden),由于他刚出生,所以他属于新生代(Young Generation)。
2. 随着程序的运行,伊甸园中的对象将会急速增长,很快这块区域将被填满,这时要保证程序继续运行,就必须清除不再使用的对象。
也就是要进行一次新生代的垃圾回收(Young GC),首先计算那些对象(假设eden和to区)不再被使用,然后还在使用中的对象我们成为幸存者。
在新生代提供了两块幸存区域(survior spaces)供幸存者使用:from和to,假设首先这部分幸存者被安排在from区(利用copy算法始终保持一个为empty,并为对象age+1.),然后eden和to区的所有对象被无情的清除,伊甸园开始继续接收新生对象。
3. 马上又到了不得不YoungGC的时间,此次检查eden和from区,幸存的对象被放入to区。
4. 不断重复2,3的过程期间一些对象经历了多次幸存游戏,我们称这些对象已经成熟,将会被移动到老年区(Old)
5. 逐渐老年区的对象也被填满,我们系统将对整个堆内存进行一次垃圾回收(full GC),这个时间明显比YoungGC的时间要长,发生的频率要小。

Java虚拟机就是不停的重复上面1,2,3,4,5的过程来维持Java世界的环境。我们通过上面的描述可以看到,想提高性能,就要尽量减少fullGC发生的频率

上图的reserved区域代表预留区域,我们先来看如何制定这几块区域的大小:
-Xmx可以指定整个堆内存的最大值。
-Xms可以指定整个堆内存的最小值,也就是初始化值,系统启动时按初始化值分配堆内存空间,内存使用超过初始值会启动两边的reserve区域,超过最大值汇报OutOfMemory:heap space异常
-XX:NewSize可以指定新生代的最小值。
-XX:MaxNewSize可以指定新生代的最大值。
老年代的最小值可以用Xms-XX:NewSize计算得出,所以不需要进行特别指定。
老年代的最大值可以用Xms-XX:MaxNewSize计算得出,所以不需要进行特别指定。

方法区(Perm Space)

这部分主要存储的类的定义,只有在进行类加载的时候才会往这个区域内增加内容,所以这个区域基本上不涉及到太多的变化因素。
在系统启动时和动态加载jar文件,class文件时,会增加这块区域的数据,如果Jar包过多,撑破这块区域则汇报OutOfMemory:perm space异常。
我们可以通过-XX:PermSize和-XX:MaxPermSize来指定这块区域的最小,最大值。

 

JVM常见的调优参数

 -Xmx  指定java程序的最大堆内存

 -Xms  指定初始堆内存, 通常设置成跟最大堆内存一样,减少GC

 -Xmn  设置年轻代大小。整个堆大小=年轻代大小 + 老年代大小。所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8

 -Xss   指定线程的最大栈空间, 此参数决定了java函数调用的深度, 值越大调用深度越深, 若值太小则容易出栈溢出错误(StackOverflowError)

 -XX:PermSize  指定方法区(永久区)的初始值,默认是物理内存的1/64, 在Java8永久区移除, 代之的是元数据区, 由-XX:MetaspaceSize指定

 -XX:MaxPermSize   指定方法区的最大值, 默认是物理内存的1/4, 在java8中由-XX:MaxMetaspaceSize指定元数据区的大小

 -XX:NewRatio=n  老年代与年轻代的比值,-XX:NewRatio=2, 表示老年代与年轻代的比值为2:1

 -XX:SurvivorRatio=n  Eden区与Survivor(2个)区的大小比值,-XX:SurvivorRatio=8表示Eden区与Survivor区的大小比值是8:1:1,因为Survivor区有两个(from, to)

 

JVM 调优建议

通过设置我们希望达到一些目标:

  • GC的时间足够的小
  • GC的次数足够的少
  • 发生Full GC的周期足够的长

前两个目前是相悖的,要想GC时间小必须要一个更小的堆,要保证GC次数足够少,必须保证一个更大的堆,我们只能取其平衡。

1)针对JVM堆的设置一般,可以通过-Xms -Xmx限定其最小、最大值,为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,我们通常把最大、最小设置为相同的值。

2)年轻代和年老代将根据默认的比例(1:2)分配堆内存,可以通过调整二者之间的比率NewRadio来调整二者之间的大小,为了防止年轻代的堆收缩,我们通常会把-XX:newSize -XX:MaxNewSize设置为同样大小

 年轻代和年老代设置多大才算合理?

更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC
更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率。

如何选择应该依赖应用程序对象生命周期的分布情况

如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性,在抉择时应该根据以下两点:

A.本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理。

B.通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1。但应该给年老代至少预留1/3的增长空间。
4)在配置较好的机器上(比如多核、大内存),可以为年老代选择并行收集算法: -XX:+UseParallelOldGC ,默认为Serial收集。

5)线程堆栈的设置:每个线程默认会开启1M的堆栈,用于存放栈帧、调用参数、局部变量等,对大多数应用而言这个默认值太了,一般256K就足用。理论上,在内存不变的情况下,减少每个线程的堆栈,可以产生更多的线程,但这实际上还受限于操作系统。

 



 

待续。。。

调优相关

 https://blog.csdn.net/chen77716/article/details/5695893

实战

https://blog.csdn.net/weixin_34327223/article/details/85600787

 https://blog.csdn.net/cml_blog/article/details/81057966

Guess you like

Origin www.cnblogs.com/dingpeng9055/p/11432017.html