一、JVM内存区域
线程共有:
方法区:用于存放被JVM加载的类信息、常量、静态变量、即时编译器编译的代码
永久代:存放的是class、method等元信息、类信息,常量,静态变量 不会被GC回收,他们会一直占用内存
jdk1.6、1.7时候:方法区指的就是永久代
jdk1.8时:方法区指的就是元空间
堆:所有的对象实例的创建都在堆内存中,所以会出现垃圾回收的操作
新生代:新创建的对象存放的位置(Eden、S0、S1)
老年代:新生代未回收的对象会被copy到老年代
程序计数器:当前线程执行字节码的行号指示器
线程私有:
虚拟机栈:java方法执行的内部模型、每个方法执行都会创建一个栈帧(),每个方法从开始调用到结束都对应一个栈帧在虚拟机上从入栈到出栈的过程
本地方法栈:java执行本地方法
直接内存(堆外内存):一部分是不需要jvm管理的直接内存,也被称为堆外内存。堆外内存就是把内存对象分配在JVM堆意外的内存区域,这部分内存不是虚拟机管理,而是由操作系统来管理,这样可以减少垃圾回收对应用程序的影响
二、JVM内存溢出
-
堆溢出
堆是存放实例对象的,那我们就无线创建实例对象。这样堆区迟早会满
解决方案:
设置jvm值的方法是通过-Xms(堆的最小值),-Xmx(堆的最大值) -
虚拟机栈/本地方法栈
方法调用层次过多(比如存在无限递归调用)
解决方案:
审查代码、修改程序
通过 -Xss: 来设置每个线程的Stack大小即可 -
方法区
-
直接内存
-
元空间
导致OutOfMemoryError异常的常见原因有以下几种:① 检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢 出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。 ② 检查代码中是否有死循环或递归调用(递归调用时未给定中止条件)。 ③ 检查是否有大循环重复产生新对象实体。 ④ 检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这 些对象不能被GC回收;导入导出IO流未关闭流(应把close放在try..catch..finally的finally中)。 处理流异常可参考:https://www.cnblogs.com/yhqtv-com/p/12880554.html
查看内存使用情况:
1、 jstat -gc pid
可以显示gc的信息,查看gc的次数,及时间。
其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。2、ps -ef | grep tomcat
ps -ef 的意思是以长格式显示所有进程
“|”是管道,意思是前面ps的输出做为后面的输入,然后grep tomcat是在所有进程里查找与字符tomcat有关的进程,并显 示出来。
三、垃圾回收
-
判断对象是否可回收
-
回收算法
-
垃圾收集器
-
垃圾回收过程
四、性能优化
如何减少GC
- 尽量减少临时对象的使用
对象不用的时候尽量显示为null - 尽量使用stringbuffer代替string
因为string是一个常量 对string的操作是创建新对象回收旧对象的一个操作,而stringbuffer和stringbuilder是变量,是对对象直接进行修改,不进行创建对象和回收旧对象的操作,不占用内存 - 能有基本数据类型int long就不用引用数据类型
基本数据类型占用的内存资源比相应的引用数据类型占用的少
五、类加载
参考链接:https://blog.csdn.net/qq_41701956/article/details/81664921