(OOM)OutOfMemoryError:内存的溢出,(包括4种溢出)Java堆溢出,虚拟机栈和本地方法栈溢出,方法区和运行时常量池溢出,本机直接内存溢出
1.jvm里面有个oom(内存溢出),当时JVM发生内存溢出时,这个进程就停止了。
2.linux也有个oom(内存溢出):当系统检测出,内存不够用,会自动kill掉内存占用高的程序。所以说在实际生产环境当中,会监控服务器的内存状况,当内存占用达到阈值的时候,会发出告警。(或者说如果用到了K8s等容器化管理技术,系统会自动扩容)
设置虚拟机启动参数的目的:如果不限制jvm启动参数(不限制堆大小,不限制栈大小,他会默认是无限的,会不断的占用服务器的内存,直到服务器发生oom,影响到其他程序)
1.堆溢出:最常见的场景就是大list,list里面有很多元素。
堆溢出怎么解决:
(1,应该定位到导致内存溢出的对象
(2,判断是否真的是内存溢出。先判断这个对象是不是正常的。如果不是,就得修复。如果调优,通过优化逻辑来减少对象的大小,如果说硬件设施(操作系统)剩余内存还足够大,就可以将堆内存调大一些。
2.栈溢出:最常见的场景就是递归调用方法,没有递归出口
栈溢出情况:
1)如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
2)如果虚拟机的栈内存允许动态扩展,当扩展栈容量无法申请到足够的内存时,将抛出OutOfMemoryError异常。
3.什么是栈溢出?什么是堆溢出?什么是堆内内存?什么是堆外内存(直接内存)?
栈溢出:是由于C语言系列没有内置检查机制来确保复制到缓冲区的数据不得大于缓冲区的大小,因此当这个数据足够大的时候,将会溢出缓冲区的范围。
堆溢出:的产生是由于过多的函数调用,导致调用堆栈无法容纳这些调用的返回地址,一般在递归中产生。堆溢出很可能由无限递归(Infinite recursion)产生,但也可能仅仅是过多的堆栈层级。
堆内内存:java的内存分为堆内内存和堆外内存,在了解堆外内存之前,先看看堆内内存是啥,堆内内存是受jvm管控的,也就是说,堆内内存由jvm负责创建和回收;创建和回收都是自动进行的,不需要人为干预;
堆外内存和堆内内存他俩是没有任何关系的;当我们在使用堆内内存的对象时,如果对象内存占用超过了申请的堆内存,就会产生OOM异常(内存溢出);而堆外内存是直接向操作系统申请新的内存空间,理论上只要操作系统的内存足够,堆外内存想申请多少都行
堆外内存(直接内存):堆外内存又叫直接内存,是和操作系统内存直接挂钩的,堆外内存不受jvm的管制,所以可以认为堆外内存是jvm以外的内存空间,虽然不受jvm管控,但是堆外内存还是在java进程里面的,而不是由系统内核直接管理;所以它还是在java进程里面的;
String.inturn():
String.intern()是一个本地方法,它的作用是如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用;否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
String str1="";
System.out.println(str1.intern() == str1);
String str2=new String("");
System.out.println(str2.intern() == str2);
String str3 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str3.intern() == str3);
String str4 = new StringBuilder("ja").append("va").toString();
System.out.println(str4.intern() == str4);
str1:String直接在字符串常量池里面创建字符串,所以值等于地址
str2:String new先在堆里面创建字符串,再把字符串放到字符串常量池里面,所以值不等于地址
str3:Sting里StringBuilder的append方法toString的intern,因为之前没有"计算机软件"这个字符串,intern返回的是新创建的地址,所以值等于地址
str4:String里StringBuilder的append方法toString的intern,因为之前有"java"这个字符串,intern返回的是之前存在的那个字符串的地址,所以值不等于地址