Java内存模型:是多线程里面的,jmm与线程可见性有关
Java内存结构:是JVM虚拟机存储空间。
Java内存机构分为:方法区、java堆、栈、本地方法栈。
方法区(永久区):就是使用static关键字修饰的基本就是存放在方法区内。
一般来说都是存放常量信息,在类加载的时候就会被初始化。
方法区就是全局的。所有线程都会被共享的。
包括静态工厂创建的对象。只要被static修饰的
Java堆:创建的对象、new创建的、数组存放在堆内存。 调优策略就是调堆。
堆所有的线程会被共享的。
栈:定义基本的局部变量、局部方法、类的方法。
栈代码运行完毕后就会自动释放内存。
栈是每个线程都是私有的。 互不共享,不会产生线程安全问题。
本地方法栈:主要是调用C语言的。jni
1、在项目中,少定义static常量。否则垃圾回收机制根本就不会回收。
2、调优主要调堆。
3、尽量减少垃圾回收机制的次数,因为垃圾回收的时候线程会被卡死,当然时间很短
感受不到就是。
4、新生代回收次数尽量比老年代多。
垃圾回收机制:不定时的去回收堆内存空间的资源。
什么是堆?new 出来的对象都会存放在堆内存中。
堆内存中分配两个区:新生代、老年代。目的就是垃圾回收机制。
垃圾回收机制主要是回收新生代里面的对象。
新生代又分为:eden区、s0区、s1区。 s0区与s1区大小相等,
目的是垃圾回收机制复制算法。
新生代:刚创建对象时候先存放在新生代。
老年代:如果对象在频繁的使用,对象会放在老年代。
在jvm刚创建对象的时候会先放在eden区。
垃圾回收机制需要经常区老年代回收垃圾吗?
不需要,因为老年代都是频繁使用的对象。回收较少。
垃圾回收机制主要回收新生代。
如图:
参数配置:
-XX:+PrintGC 每次触发GC的时候打印相关日志
-XX:+UseSerialGC 串行回收
-XX:+PrintGCDetails 更详细的GC日志
-Xms 堆初始值
-Xmx 堆最大可用值
-Xmn 新生代堆最大可用值
-XX:SurvivorRatio 永安里设置新生代中eden控件和from/to空间比例。
含义:-XX:SurvivorRatio=eden/from=den/to
总结:在实际工作的时候,我们可以直接将初始堆大小与最大堆大小配置相等。
这样的好处是可以减少程序运行时垃圾回收次数。从而提高效率。
代码:查看堆内存和使用内存
package com.leeue;
import java.text.DecimalFormat;
/**
*
* @classDesc: 功能描述:(配置堆内存初始值大小要与堆最大内存值相等。)
* @author:李月
* @Version:v1.0
* @createTime:2018年7月31日 下午2:57:53
*/
public class Demo {
public static void main(String[] args) throws InterruptedException {
JvmInfo();
byte[] bytes01 = new byte[1*1024*1024];
System.out.println("分配了1M");
Thread.sleep(2000);
JvmInfo();
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);// 返回的是String类型
return s;
}
public static void JvmInfo() {
//最大内存配置信息
long maxMemory = Runtime.getRuntime().maxMemory();
System.out.println("最大内存配置:"+maxMemory+","+toM(maxMemory)+"M");
//当前空闲内存
long freeMemory = Runtime.getRuntime().freeMemory();
System.out.println("当前空闲内存:"+freeMemory+","+toM(freeMemory)+"M");
//已使用内存
long totalMemory = Runtime.getRuntime().totalMemory();
System.out.println("已使用内存:"+totalMemory+","+toM(totalMemory)+"M");
}
}
-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags
这里配置了初始值是5M 最大值是20M
设置完成后 垃圾回收机制回收了两次
-Xmn 新生代大小,一般设为整个堆的1/3到1/4左右
-XX:SurvivorRatio 设置新生代中eden区和from/to空间的比例关系n/1
参数:
-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
-XX:SurvivorRatio 设置新生代中eden区和from/to空间的比例关系n/1 如下图
这个参数是配置新生代与老年代的比例关系
-Xms20m -Xmx20m
-XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=2
-XX:NewRatio=2 表示新生代与老年代的关系是2:1 新生代占两份
1、设置初始堆大小要与最大堆大小配置相等。
2、设置新生代与老年带回收比例。
JVM参数调优,怎么让垃圾回收机制经常区新生代进行回收?
答:新生代与老年代比例1/3或1/4
堆溢出:
解决方案:
-Xms1m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
栈溢出:产生于递归调用,循环遍历是不会出现栈溢出的。但是循环方法里
产生递归调用也会发生栈溢出
解决方案:设置线程最大调用深度
-Xss5m 设置线程最大调用深度。
JAVA_OPTS="-server -Xms800m -Xmx800m
-XX:PermSize=256m -XX:MaxPermSize=512m
-XX:MaxNewSize=512m"