配置堆内存大小,其实比较简单,你们以后做JVM调优,主要是围绕着哪个内存区域,都是围绕着堆内存的,像栈每次
用完之后都会自动释放的,还有方法区,但是方法区你不用考虑,因为它如果满的情况下,垃圾回收会自动去回收,但是主要还是围绕
堆内存的,我们怎么去配置堆内存大小,在这里给你们介绍几个方法
package com.learn.test;
/**
* 我们怎么去配置堆内存大小
* 打印一下堆内存的一些基本的大小
* @author Leon.Sun
*
*/
public class Test001 {
public static void main(String[] args) {
/**
* 4 * 1024 * 1024这样是4个兆的空间
* 你们猜一下已使用内存是多少兆
* 是不是至少在9M以上
* 5家4嘛
* 可不可能小于9兆
* 肯定是大于9M以上
* 你们想想是不是这样的
* 已经使用内存10M
* 我们运行是不是这样的
* 10M
* 为什么会多出1兆出来
* 因为它底层也会做一些处理操作的
* 可能有误差
* 但是误差不大
* 一般在几兆左右
* 肯定是会大于9M以上的
* 这个是堆内存大小
* 过来我会将内存泄露怎么解决
* 这个配置JVM堆内存的大小应该不难吧
* 我这里能不能配置25M
*/
// byte[] b = new byte[4 * 1024 * 1024];
/**
* 我能不能申请25M的空间
* java.lang.OutOfMemoryError: Java heap space
* 这个你们遇见过是不是
* 我只是演示一个效果
* 待会讲怎么解决
* 一开始的时候为什么不会溢出
* -Xmx20m -Xms5m
* 我把这个配置删掉
* 因为一开始默认是4个G的内存
* 这绰绰有余
* 肯定是没有任何影响的
* 你看这个就没有溢出了
* 堆内存配置的话比较容易
*
*/
byte[] b = new byte[25 * 1024 * 1024];
System.out.println("分配了25M空间给数组");
/**
* 打印JVM一些基本的参数
* 第一个参数表示堆的最大内存
* 最大内存1803M
* 你们知道他们是按照什么单位来换算的
* 兆的下一个单位是字节
* 他这个比较小
* 你们最好是/1024/1024
* 这样就换算成兆了
* 你们看到1803M
* 1803M大概等于多少G呢
* 差不多2个G
* 可能有一些内存被占用掉了
* 默认是4个G的
* 可能你的电脑打印出来也不一样
* 因为每台电脑都不一样
* 所以多多少少会有点误差
* 你们都按照四舍五入去算就行了
* 默认都是4个G的内存
* 我以前带电脑是8个G的时候默认是8个G的
* 这是默认的
* -Xmx20m -Xms5m
* 这个参数什么意思
* 表示我当前最大可用堆内存是20M
* 然后初始的是为5M
* 你们找到Run as里面
* 然后Run Configuration
* 然后你把参数就放到Arguments的VM arguments
* 表示我这个项目启动起来之后,
* 他最大的堆内存是20M
* 他的初始值是5M
*
* 最大内存18M
* 有的人说不对啊
* 我明明设置的是20M
* 怎么变成18M了
* 我已经讲过了
* 这个多多少少会有点误差
* 但是大家不要去纠结这个误差
*
*/
System.out.println("最大内存" + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "M");
/**
* 第二个可用的内存
* 可用内存96M
* 默认可用的是96M
*
* 可用内存4M
*/
System.out.println("可用内存" + Runtime.getRuntime().freeMemory() / 1024 / 1024 + "M");
/**
* 已经使用的内存
* 已经使用内存123M
*
* 已经使用内存5M
* 这个时候可以看到已经使用的内存是5M
* 这个已经使用的内存是什么意思吗
* 已使用的内存是根据你初始值申请来的
* 你在这边可以看一下
* -Xmx20m -Xms5m
* 在这边我申请的初始值是5m
*/
System.out.println("已经使用内存" + Runtime.getRuntime().totalMemory() / 1024 / 1024 + "M");
}
}
首先这个是堆内存,堆内存新生代和老年代一般是1:2,左边我们叫做新生代,右边叫做老年代,新生代又有一个eden区,
接着还有S0区和S1区,S0还有一个名字叫from区,默认的是8:1:1,这个看你们公司,每个公司的项目不一样,eden区比S0区大了还是小了
记住肯定是要大的,S0区和S1区的主要作用是干嘛,做复制功能,你没必要把它搞的特别大,特别大的情况下会特别的占用内存的,
所以默认情况是8:1:1,其实8:1:1也不是很好,如果我对象特别多的情况下,你如果还是做成8:1:1的情况下,你知道会产生什么情况吗,
s0区可能装不满的,所以也会导致频繁的GC的回收,所以要看你在什么应用场景,我看过我们的项目是怎么配的呢,就是2:1:1,
但是我们的项目比较大,绝大部分的对象还是会存放到老年代里去的,根据不同的公司,这个看你们公司的,我们配置新生代的比例,
我们讲一个参数,-XX:+PrintGCDetails这个参数,这个参数谁知道是干嘛用的,打印详细的GC日志,GC日志到时给你演示一遍,当它
发生GC回收的时候,都会打印一个GC日志
package com.learn.test;
/**
* 配置新生代比例大小
* 什么是新生代
* 我们刚出生的都是在eden区里面
* 如果eden区满的时候会GC的
* @author Leon.Sun
* -Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
* 首先堆内存是20M
* 堆内存最大值是20M
* 新生代-Xmn最大值是1M
* eden区和s0/s1区的比例是2:1
* -XX:SurvivorRatio这个参数干嘛用的
* 它是配置eden区和from/to区的一个比列
* 用来设置新生代eden空间和from/to空间的比例
* from区和to区的比例都是相等的
* 相当于eden区占两份,
* S0区占一份,S1区也占一份
* 第一次你是看到配置的选项的,
* 你要先运行这个JAVA代码
* 然后你就可以去Run as -> Run Configration看到记录
* 然后你就可以配置VM arguments
* 这个说细点
* 免得你们下次不知道怎么配了
* -Xms20m -Xmx20m -Xmn2m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
* [GC (Allocation Failure) [DefNew: 1024K->512K(1536K), 0.0014710 secs]
* 这个表示空间不够了进行回收垃圾
* 首先你们可以看到这几个参数
* eden space 1024K
* 首先可以看到eden区
* eden区是1024K
* from space 512K
* from区是512K
* to space 512K
* to区是512K
* -XX:SurvivorRatio=2这个参数配置什么意思
* SurvivorRatio=2 配置新生代中 eden from to 比例关系 2 1 1
* 1024K除以2是不是512K了
* -Xms20m -Xmx20m -Xmn2m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
* 我们把这个配置删掉
* 我们只留-XX:+PrintGCDetails -XX:+UseSerialGC这个信息
* 只留GC的日志信息
* -XX:+UseSerialGC这个是配置串行回收
* 这个时候我们来运行一遍来看这个效果
* 你们有没有发现一个问题
* 这一次运行没有发生GC回收的
* 你们有没有仔细观察
* -Xms20m -Xmx20m -Xmn2m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
* 我这个时候把堆内存设置为20M
* 堆内存最大内存为20M的情况下
* 他就会发生一个GC日志[GC (Allocation Failure)
* 那这个GC日志是什么GC
* 你们说这个程序运行的时候需要几兆
* 运行的时候至少是需要10M以上
* 因为我循环了10次
* 但是你新生代只有2m
* 你新生代是2兆
* 这个时候你又要装10兆
* 你要往新生代放10次2M的话
* 新生代空间根本就不够
* 因为新生代只有2M内存
* 这样我就不够用
* 为了防止内存溢出的情况下
* 包括防止内存泄露的情况下
* 我就不停的进行回收
* 这样我才有新的可以进来
* 如果内存不足的情况下会发生不断地去进行回收的
* 如果内存非常足的情况下他去回收干嘛
* 类似与我们生活中你那么有钱你还要去抢钱干嘛
* 其实是一个道理
* 你们可以算一下
* 默认的我们可以算一下
* 34944K除以4352K等于8
* 你们觉得这个比例是多少
* 8:1:1
* eden:from:to
* 你们如果仔细算有点误差也是很正常的
* 不要纠结少了几十K
* 这个很正常
*
*/
public class Test002 {
public static void main(String[] args) {
byte[] b = null;
for (int i = 0; i < 10; i++) {
b = new byte[1 * 1024 * 1024];
}
}
}