目录
Java内存模型(多线程,可见性)
Java内存结构(虚拟机存储空间)
方法区:全局的,存于永久区,所有线程共享,static修饰
public static Demo001 demo001=new Demo001();
堆:所有线程共享 新生代,老年代,s0区,s1区,from区
public Demo001 demo001=new Demo001();
栈:每个线程私有,类的方法
JNI:java调用C语言
pc寄存器:1线程私有 2有指针,计算变量
执行引擎:执行字节码文件
堆 :新生代+edn区+s0区+s1区+老年代
垃圾回收机制不会经常在老年代进行回收垃圾,主要回收新生代;
老年代放着经常使用的对象
JVM参数调优
堆的参数配置
-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags
IDEA设置虚拟机参数
第一步:打开“Run->Edit Configurations”菜单
第二步:选择“VM Options”选项,输入你要设置的VM参数
public class Demo002 {
public static void main(String[] args) throws InterruptedException {
byte[] bytes01 = new byte[1 * 1024 * 1024];
System.out.println("分配1m内存");
jvmInfo();
Thread.sleep(1000);
byte[] bytes02 = new byte[4 * 1024 * 1024];
System.out.println("分配4m内存");
jvmInfo();
}
static private String toM(long maxMemory) {
float num =(float) maxMemory / (1024 * 1024);
DecimalFormat df = new DecimalFormat("0.00");//格式化小数
String s = df.format(num);
return s;
}
public static void jvmInfo(){
//最大内存配置
long maxMemory = Runtime.getRuntime().maxMemory();
System.out.println("最大内存配置maxMemory::"+maxMemory +","+toM(maxMemory)+"M");
//当前空闲内存
long freeMemory = Runtime.getRuntime().freeMemory();
System.out.println("当前空闲内存freeMemory::"+freeMemory +","+toM(freeMemory)+"M");
//已使用内存
long totalMemory = Runtime.getRuntime().totalMemory();
System.out.println("已使用内存totalMemory::"+totalMemory +","+toM(totalMemory)+"M");
}
}
-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags
运行结果 GC回收两次
-Xms20m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags
运行结果 GC回收一次
-Xms1000m -Xmx1000m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags
运行结果 GC不用回收
JVM调优,让垃圾回收机制经常去新生代 进行回收?
新生代:老年代比例 1:3或者1:4
新生代和老年代优化参数
-Xms: 新生代大小,占整个堆的1/3到1/4左右
-XX:SurvivorRatio 默认为8:设置新生代中eden区和from/to空间的比例关系n/1
设置新生代比例参数-XX:SurvivorRatio=2
参数
-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
public class Demo004 {
public static void main(String[] args) {
//-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
//-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=2
byte [] bytes=null;
for (int i = 0; i <10 ; i++) {
System.out.println("i"+i);
bytes=new byte[1*1024*1024];
}
}
}
结果
新生代中eden区和from/to空间的比例关系2/1
eden区和from和to=-Xmn1m
设置新生代与老年代参数
减少新生代回收,增加老年代回收
参数
-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=2
内存溢出解决方法
设置堆内存大小
-Xms1m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
设置为下面参数不报错--服务器端开发
-Xms10m -Xmx40m -XX:+HeapDumpOnOutOfMemoryError
Tomcat配置
设置栈内存大小
栈溢出 方法递归调用,不是循环调用方法发生
栈溢出--无限递归使用
-Xss5m
gc 垃圾回收机制和算法分析
Java垃圾回收机制
判断对象是否会被清理掉,是否可达(finalize)
定义后对象被引用,可达;定义后对象不被引用,不可达
public class Test001 {
public static void main(String[] args) {
//初始化堆内存 设置小,容易被回收
Test001 test001 = new Test001();
test001=null;//赋值为空会回收
Test001 test002 = test001;
System.gc();//手动回收垃圾
}
@Override
protected void finalize() throws Throwable {
//gc回收之前调用,不会百分百调用
System.out.println("垃圾回收机制之前....");
}
}
内存溢出和内存泄露
内存溢出:项目需要4g内存,项目只是支持3g内存 浪费了
内存泄露:定义许多静态变量,占用许多资源,不能放在栈中,垃圾不会回收,对象没有引用,报内存泄露,没有被浪费,是不够用
内存泄露 :是指程序在申请内存后,无法释放已申请的内存空间就造成了内存泄漏,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。
我们知道了内存泄漏的原因而内存溢出则有可能是因为我们我们多次内存泄漏堆积后的后果则变成了内存溢出
内存溢出: 指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出,简单来说就是自己所需要使用的空间比我们拥有的内存大内存不够使用所造成的内存溢出。
垃圾回收机制算法
引用计数法:做标记,每个堆内存的每个对象都有15次机会,当不可达,减一,直到减到0,gc回收
标记压缩是标记清除的升级
分代算法:新生代,老年代
引用计数法
每个对象都有一个标记,默认15次,gc线程发现user没使用,user还有14次,过了一段时间,gc线程又发现user没有使用,user还有13次;过了一段时间,gc发现user对象引用,加一,14次
大于15次,会进入s0,s1,老年代
复制算法-新生代(s0 =s1)
s0区和s1区
1 new出来的对象user,先进入eden区,gc发现经常被使用,user进入s0区
又new出来的对象user2,先进入eden区,gc发现经常被使用,user2仍会进入s0区
s0和s1只能保证一个区里面放着存活对象,不放不存活对象
2如果gc发现user不可达,user2经常使用,会把user2复制到s1区,然后清除s0区
3 如果又new一个user3和user4,经常被使用,会从eden进入s1区,如果gc发现user3没有经常使用,
那么user2和user4会复制s0区,同时清除s1区,这样s0存放存活对象
好处:连续性,不会产生碎片
eden区20多次进入s1或者s0,有三四十次进入老年代
标记清除算法(有残留)老年代
0可达 1不可达
创建user,user2,user3....对象,在堆内存中,标记0可达
如果user不经常使用,不可达,标记1不可达 ,清除时,只删除位置,不连续删除---改进为标记压缩算法
标记压缩算法(标记清除算法的改进)老年代
把不可达对象放在前面,可达放在后面
分代收集算法
老年代垃圾回收机制很少回收
垃圾回收机制会频繁执行会降低程序效率
回收时候,其他线程会停顿,不允许其他对象进入
垃圾收集器
串行回收器--单线程收集垃圾--效率低;并行回收器--多线程-效率高(面试区别)
串行收集器
并行回收器
---新生代的垃圾收集器
---老年代的垃圾收集器
Tomcat配置调优测试
Jmeter压力测试工具
测试吞吐量(串行)
每秒成功多少次
JVM调优属于高并发调优一部分
项目启动6次gc回收
请求接口
扩大堆的内存(串行)
为512M,初始内存不变为-Xms32M
初始值不变,加上堆内存后项目启动还是6次gc回收---调整初始值
调整初始值(串行)
和最大值一样
没有gc回收,吞吐量492
并行回收(UseParNewGC)新生代
吞吐量比串行高
并行合并回收(UseParallelGC)
线程数为8(2*核数)8线程