我们讲一下堆溢出,栈溢出,还有方法区的溢出,这就讲了一个概念,内存溢出和内存泄露的区别是什么,这个概念很混淆,
内存泄露怎么又包含内存溢出,内存溢出和内存泄露又有区别,待会我会细讲的,堆溢出我们怎么去解决,你们基本上都遇到过堆溢出没有,
堆溢出,就是申请的空间不足了,把内存空间加大一点就行了,这个时候我就来演示一把
package com.learn.test;
import java.util.ArrayList;
import java.util.List;
/**
* 内存溢出问题
* 初始化加载的比较多
* 我开始做Spring项目的时候
* 我刚学JAVA的时候
* 做SSH进行整合的时候
* 报了一个内存溢出
* 去百度找方案
* 加内存
* 那时候还没有学JVM
* 为什么加堆内存大小能解决问题
* 学JVM的时候才知道整个原理
* 电脑只有2个G的内存
* 经常做Spring项目的时候
* 经常会发生内存溢出的问题
* 电脑根本跑不起一些项目
* 这个会出现内存溢出的问题
* 怎么去演示
* 这段代码至少需要几兆的空间
* 这段代码执行至少需要几兆内存的空间大小
* 至少10M是不是
* 你们觉得配多少合适呢
* 有的人说配10M
* 配10M肯定是不行的
* 因为它可能会被其他的地方占用空间吗
* 所以10M肯定不行的
* 我在这里配置10M看一下
* -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
* 这里我的堆的初始值是1M
* 然后最大是10M
* 你会发现10M肯定是会有问题的
* 先运行一遍
* 默认是可以的,
* 因为默认值很大
* 默认是4G内存
* -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
* 我们配置这个
* 初始值是1M
* 最大值是10M
* 完全不够
* [Full GC (Allocation Failure)
* 而且这个时候有Full GC
* Full GC表示什么目的
* 如果你老年代的都不足的情况下,
* 方法区的内存不足的情况下
* 或者老年代快满的情况下
* 它会做一个全部的回收
* 把新生代和老年代都回收一下
* 为什么呢
* 你们在做开发的时候会遇到的
* 如果你们项目中内存溢出的时候
* 他首先会做一个Full GC的处理
* 目的是什么呢
* 就是把整个新生代和老年代的空间都给你回收一遍
* 看有没有可回收的
* [GC (Allocation Failure)
* 整个GC是什么GC
* 是Minor GC吗
* 一般只要发生Full GC就会发生Minor GC
* 10M肯定不够
* 我们再改一下
* 比如15M
* -Xms1m -Xmx15m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
* 15M也不一定
* -Xms1m -Xmx20m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
* 我们改20M
* 20M也不够
* 那我们到底设置多少M合适
* 我们设置100M
* -Xms5m -Xmx100m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
* 100M绰绰有余
* 而且你们有没有发现问题
* 当我最大的内存设置的比较大的情况下
* GC回收是不是不会很频繁
* 你们看到效果没有
* 刚才如果我们设置10M,20M的话
* 至少4次Minor的GC
* 发生两次Full GC
* 如果我把最大内存配置为100M的时候
* 那他只发生1次的新生代的回收
* -Xms5m -Xmx50m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
* 我们改成50M
* i:8
* 运行到第8次的时候,
* 50M都不够
* 会有Full GC
* 我估计还是配100M
*
*
* @author Leon.Sun
*
*/
public class Test0004 {
public static void main(String[] args) {
/**
* ArrayList数组其实也是有空间的
* ArrayList底层是数组
* 也是会占空间的
* 最大内存值是50M
* 这个时候是不是就够了
*/
// List<Object> listObject = new ArrayList<>();
for (int i = 0; i < 10; i++) {
System.out.println("i:" + i);
Byte[] bytes = new Byte[1 * 1024 * 1024];
/**
* 看到效果没有
* 你们在开发中定义的list其实是非常占内存的
* 我把list注掉之后就没有很多内存了
* [GC (Allocation Failure) [PSYoungGen
* 这个GC是什么GC
* 是回收新生代还是回收老年代
* 记住这是新生代回收
* [Full GC (Allocation Failure)
* 这个是新生代和老年代一起回收
* 他们到底有什么样的区别
* 有一些细节参数先不讲
* [PSYoungGen: 480K->0K(1536K)] [ParOldGen: 33008K->1017K(4096K)]
* 他已经打印出日志了
* 今天还没有细分日志的分析
* 我们下节课详细分析
* [GC (Allocation Failure) [PSYoungGen: 496K->480K(1536K)]
* 这个是新生代的日志打印
* [Full GC (Allocation Failure) [PSYoungGen: 480K->0K(1536K)]
* 这个是新生代和老年代的日志打印
* PSYoungGen这是新生代
* ParOldGen这是老年代
* 这个为什么要回收
* 你可以看一下我是怎么配的
* -Xms1m -Xmx50m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
* 初始值是1兆内存
* 因为初始值非常小
* 你这里要用10个1M内存
* 他需要不停的去回收垃圾
* 重新申请内存出来
* 就是内存不够的情况下需要去回收垃圾的
* 你如果越大的情况下就不会有这些GC日志信息的
* 如果我初始值改成50M
* -Xms50m -Xmx50m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
* 你们可以数一下一共有多少次GC日志
* 刚开始是4次,
* 现在只要3次
* 如果空间非常足
* 我就没有必要去回收了
* 我内存不足的情况下我再去回收
* 垃圾回收的基本原则
* 垃圾回收机制基本原则:内存不足的时候回去回收,内存如果足够,暂时不会区回收。 减少回收次数和回收的时间
* 因为垃圾回收会对其他的工作线程会有影响的
* 就是会暂停一下
* 你如果经常频繁的去回收
* 非常影响我整个程序的
* 你们会发现在生产环境服务器
* 一般内存都特别大
* 都是8个G,16G
* 如果内存够就不会发生垃圾回收
* 如果内存非常小垃圾回收就会频繁的去回收
* 会非常影响你整个程序的
* 回收原则就是减少回收的次数和回收时间
*
*/
// listObject.add(bytes);
}
System.out.println("添加成功...");
}
}